이 글은 [[한글자막] React 완벽 가이드 with Redux, Next.js, TypeScript]를 수강하며 정리한 글입니다.

 

 

⚛️ 기본 환경: IDE: VS code, Language: React

 

 

React.useRef()

: .current프로퍼티에 변경 가능한 값을 담고 있는 상자와 유사

 * 특정 DOM 선택 시 사용

= JavaScript에서의 특정 DOM 을 선택하는 getElementById, querySelector 같은 DOM Selector 함수와 같은 역할

 * Rerendering 방지

 = useRef로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링되지 않음

 

 

useRef() 설정

1. useRef import

1
2
import React, { useState, useRef } from "react";
 
 
 

 

2. 변수에 useRef() 할당

1
2
3
4
5
  const nameInputRef = useRef();
 
console.log(nameInputRef); // {current: input#username}
  const enteredNameRef = nameInputRef.current.value; // Max: input에 입력한 값
 
 
 

(nameInputRef tag에 사용 후, 값 출력 가능)

 

3. useRef 사용

1
2
<input id="username" type="text" ref={nameInputRef} />
 
 
 

 

⭐ useRef를 사용할 경우, 간결한 코드로 빠르게 값을 읽어올 수 있음

단, React에 의해 제어되지 않으므로 Uncontrolled Component가 됨

 = useRef는 단순히 input 태그에 입력된 값을 가져오기만 하고 값을 주입하지 않음

⭐ useState를 사용할 경우, 태그와 값을 주고받을 수 있음

React에 의해 제어되므로 Controlled Component가 됨

 = useState는 input 태그의 초기값을 설정해주고 함수를 통해서 값을 변경 및 설정함

 

 

 

참고 자료

 

Hooks API Reference – React

A JavaScript library for building user interfaces

ko.legacy.reactjs.org

 

 

[ReactJS_Complete] Controlled Component, Uncontrolled Component

이 글은 [[한글자막] React 완벽 가이드 with Redux, Next.js, TypeScript]를 수강하며 정리한 글입니다. ⚛️ 기본 환경: IDE: VS code, Language: React 1. Controlled Component : 사용자의 입력을 기반으로 state를 관리하

hj0216.tistory.com

 

이 글은 [[한글자막] React 완벽 가이드 with Redux, Next.js, TypeScript]를 수강하며 정리한 글입니다.

 

 

⚛️ 기본 환경: IDE: VS code, Language: React

 

 

ReactDOM.createPortal()

: 렌더링하려는 HTML 요소를 다른 장소로 이동

 

⭐ Modal 창 등을 root Component와 구분하여 관리

 

사용 방법

1. ReactDOM import

1
2
import ReactDOM from "react-dom";
 
 

react-dom: React의 기능을 Web browser에서 사용하기 위해 import 

= 웹브라우저에 대한 React용 어뎁터의 일종

 

2. 이동하고자하는 Component 선언

1
2
3
4
const Backdrop = (props) => {
  return <div className={classes.backdrop} onClick={props.onConfirm} />;
};
 
 
 

 

3. ReactDOM.createPortal() 사용

{createPortal(이동시키고자하는 Component, 이동하고자하는 위치의 요소 id)}

1
2
3
4
5
6
7
8
9
10
11
const ErrorModal = (props) => {
  return (
    <React.Fragment>
      {ReactDOM.createPortal(
        <Backdrop onConfirm={props.onConfirm} />,
        document.getElementById("backdrop-root")
      )}
    </React.Fragment>
  );
};
 
 
 

* document

: React는 Single Page Application을 권장하며 모든 JS파일이 index.html에 import 됨

파일은 여러개일지라도 실제 html 페이지는 1개 = index.html이며, document는 곧 index.html을 의미

→ index.html에서 root 컴포넌트와 분리하여 관리하고 싶은 요소들을 위한 태그 생성

 

4. index.html에 이동시키고자하는 위치 지정

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="backdrop-root"></div>
    <div id="root"></div>
  </body>
</html>
 
 
 

 

 

 

참고 자료

 

createPortal – React

The library for web and native user interfaces

react.dev

 

이 글은 [[한글자막] React 완벽 가이드 with Redux, Next.js, TypeScript]를 수강하며 정리한 글입니다.

 

 

⚛️ 기본 환경: IDE: VS code, Language: React

 

 

JSX에서 return 값은 1개만 가능하므로 여러 요소들이 return될 때, 1개의 tag로 감싸거나 배열을 선언해야 함(참고)

⭐ 배열 선언보다는 <div>를 통해서 1개의 return값을 만듦

 

🚨 JSX 요구사항에 따른 다수의 <div> 선언에 따른 불필요한 <div> 생성

▶ tag styling에 좋지 않

다수의 html 요소 rendering에 따른 페이지 로딩 속도 저하

 

 

<div> Soup 해결 방법

1. Wrapper.js 생성

1
2
3
4
5
6
const Wrapper = (props) => {
    return props.children;
}
 
export default Wrapper;
 
cs
1
2
3
4
5
6
7
return (
    <Wrapper>
        <h2 key="h2">Hi there!</h2>
        <p key="p">This does not work :-(</p>
    </Wrapper>
);
 
 
cs

⭐ <div>를 따로 선언해주지 않았으므로 태그를 반환하지 않지만, Wrapper Component로 감싸주어 JSX 제약사항은 만족시킴

 

2. React.Fragment 사용(Wrapper component와 동일한 기능)

1
2
3
4
5
6
7
return (
    <React.Fragment>
        <h2 key="h2">Hi there!</h2>
        <p key="p">This does not work :-(</p>
    </React.Fragment>
);
 
 
cs

+ 기능 지원 시, 축약형 사용 가능

1
2
3
4
5
6
7
return (
    <>
        <h2 key="h2">Hi there!</h2>
        <p key="p">This does not work :-(</p>
    </>
);
 
 
cs

 

cf. <React.Fragment> 와 <Fragment>

import React, { useState } from 'react'; ▶ <React.Fragment> 사용 가능

import React, { useState, Fragment } from 'react'; ▶ <React.Fragment>, <Fragment> 사용 가능

 

 

 

참고 자료

 

⚛︎ <div> soup 방지하는 방법

루트 jsx 요소는 1개여야만 한다.jsx가 js로 변환하면서 값 하나만 반환 가능하기 때문이다.그래서 인접한 요소들을 <div>로 감싸게 되는데, 불필요한 div요소가 중첩되어 <div> soup이 발생한다.wrapper

velog.io

 

 

<div> Soup 🥘 해결하기

div soup를 해결하는 세가지 방법에 대해서 다룹니다.

velog.io

 

이 글은 [[한글자막] React 완벽 가이드 with Redux, Next.js, TypeScript]를 수강하며 정리한 글입니다.

 

 

⚛️ 기본 환경: IDE: VS code, Language: React

 

 

JSX return값 1개

1
2
3
4
5
return (
    <h2>Hi there!</h2>
    <p>This does not work :-(</p>
);
 
cs

🚨 Adjacent JSX elements must be wrapped in an enclosing tag

 

 

해결방법

1. Wrapper 태그로 감싸기

1
2
3
4
5
6
7
return (
    <div>
        <h2>Hi there!</h2>
        <p>This does not work :-(</p>
    </div>
);
 
 
cs

⭐ div tag뿐만 아니라 다른 기본 html 태그도 가능하며, component 또한 가능

 

2. 배열 선언

1
2
3
4
5
return [
    <h2 key="h2">Hi there!</h2>
    <p key="p">This does not work :-(</p>
];
 
 
cs

⭐ 배열 선언 시, 효율적인 rendering을 위해 key값 선언 필요

(key값 미 선언 시, 🚨 Warning: Each child in a list should have a unique "key" prop. 경고 발생)

 

이 글은 [[한글자막] React 완벽 가이드 with Redux, Next.js, TypeScript]를 수강하며 정리한 글입니다.

 

 

⚛️ 기본 환경: IDE: VS code, Language: React

 

 

 

 

1. Setting Dynamic Inline Styling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  return (
    <form onSubmit={formSubmitHandler}>
      <div className="form-control">
        <label style={{ color: !isValid ? "red" : "black" }}>Course Goal</label>
        <input
          style={{ border: !isValid ? "1px solid red" : "1px solid #CCC" }}
          type="text"
          onChange={goalInputChangeHandler}
        />
      </div>
      <Button type="submit">Add Goal</Button>
    </form>
  );
 
 
cs

 

2. Setting CSS Classes Dynamically

1
2
3
4
5
6
7
8
9
10
  return (
    <form onSubmit={formSubmitHandler}>
      <div className={`form-control ${!isValid ? 'invalid' : ''}`}>
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </div>
      <Button type="submit">Add Goal</Button>
    </form>
  );
 
 
cs
1
2
3
4
5
6
7
8
9
.form-control.invalid input {
  border-color: salmon;
  background-color: #ffd7d7;
}
 
.form-control.form-control.invalid label {
  color: salmon;
}
 
 
cs

 

3. Using Styled Library1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const FormControl = styled.div`
   {
    margin: 0.5rem 0;
  }
 
  & label {
    font-weight: bold;
    display: block;
    margin-bottom: 0.5rem;
  }
 
  & input {
    display: block;
    width: 100%;
    border: 1px solid #ccc;
    font: inherit;
    line-height: 1.5rem;
    padding: 0 0.25rem;
  }
 
  & input:focus {
    /*input:focus, input type에 focus가 들어왔을 때*/
    outline: none;
    background: #fad0ec;
    border-color: #8b005d;
  }
 
  &.invalid input {
    border-color: salmon;
    background-color: #ffd7d7;
  }
 
  &.invalid label {
    color: salmon;
  }
`;
 
 
const CourseInput = (props) => {
  return (
    <form onSubmit={formSubmitHandler}>
      <FormControl className={!isValid && 'inValid'}>
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </FormControl>
      <Button type="submit">Add Goal</Button>
    </form>
  );
};
 
 
cs

 

4. Using Styled Library2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const FormControl = styled.div`
   {
    margin: 0.5rem 0;
  }
 
  & label {
    font-weight: bold;
    display: block;
    margin-bottom: 0.5rem;
    color: ${props => props.invalid ? 'tomato' : 'black'};
  }
 
  & input {
    display: block;
    width: 100%;
    border: 1px solid ${props => (props.invalid ? 'tomato' : '#ccc')};
    background: ${props => props.invalid ? '#ffd7d7' : 'transparent'};
    font: inherit;
    line-height: 1.5rem;
    padding: 0 0.25rem;
  }
 
  & input:focus {
    /*input:focus, input type에 focus가 들어왔을 때*/
    outline: none;
    background: #fad0ec;
    border-color: #8b005d;
  }
 
`;
 
 
const CourseInput = (props) => {
  return (
    <form onSubmit={formSubmitHandler}>
      <FormControl invalid={!isValid}>
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </FormControl>
      <Button type="submit">Add Goal</Button>
    </form>
  );
};
 
 
cs

 

5. Using CSS Module

1
2
3
4
5
6
7
8
9
10
11
12
  return (
    <form onSubmit={formSubmitHandler}>      <div className={`${styles['form-control']} ${!isValid && styles.invalid}`}>
      {/* className에 -가 들어가는 경우, ''로 감싼 후 []로 감싸기
      styles['form-control']: form-control이라는 클래스를 styles 객체에서 가져오기 → output: form-control
      !isValid && styles.invalid: isValued 초기값-true, && 첫 번째 피연산자가 false로 평가되는 경우 그 값을 반환 → output: inValid
       */}
        <label>Course Goal</label>
        <input type="text" onChange={goalInputChangeHandler} />
      </div>
      <Button type="submit">Add Goal</Button>
    </form>
  );
cs