리액트의 특징

  • 컴포넌트로 반복되는 부분을 하나의 구성요소로 만들어 코드를 재사용할 수 있다.
  • state를 사용할 수 있다.
  • virtual dom: 페이지 로드 시 연산이 줄어들고 리소스를 재활용하기 좋다. (처음에는 로드하느라 조금 느릴 수 있지만 그다음부터는 페이지 전환이 빠름)
  • 단방향 데이터 바인딩

단방향 데이터 바인딩

데이터 바인딩 : 화면에 보이는 데이터와 브라우저 메모리에 있는 데이터를 일치시키는 것

양방향 데이터 바인딩의 경우, 데이터의 변화를 감시하는 watcher가 두개라 컨트롤러(자바스크립트)와 뷰(HTML)에서 데이터가 변경될 수 있다.
단방향 데이터 바인딩의 경우 템플릿과 모델(데이터)을 합쳐 뷰에 반영한다. 자바스크립트의 데이터가 HTML에 표현되므로 단방향 데이터 바인딩을 하면 데이터의 변화를 예측/감지하기 쉽고, 데이터를 추적하거나 디버깅하는 데 용이하다.

리액트의 라이프사이클 함수 (생애주기)

  1. constructor()
  2. componentWillMount()
  3. render()
  4. componentDidMount()

클래스 컴포넌트

  • 옛날 문법
  • render() 안에서 return

함수 컴포넌트

  • 함수(function)를 기반으로 작성
  • 클래스 컴포넌트의 componentDidMount는 함수 컴포넌트의 useEffect로 대체 가능하다.

리액트 개발 시 주의할 점

  • react 사용할땐 DOM 직접 조작을 피하자. 변경하려는 유일한 것은 state여야 한다.
  • 리액트에서 prop을 주고 받을때 필요한 컴포넌트가 여럿 넓게 펼쳐져 있는 경우, 주고 받기 복잡하고 유지보수 또한 어려워진다. 그럴땐 리액트 자체 Context API를 사용하면 좋다. 필요한 상태가 있는 컨텍스트를 따로 만들어두고 필요할 때 그때그때 값을 사용할 수 있다.

리액트 최적화 방법

  1. useMemo로 복잡한 연산이 필요한 함수는 캐싱. 함수의 디펜던시(파라미터)가 같을 경우 이전에 리턴했던 참조값을 재사용함.
  2. 클래스 컴포넌트에서는 React.memo로 메모이제이션 (useMemo와 같음)
  3. useCallback으로 함수 선언을 메모이제이션
  4. 자식 컴포넌트에게 props를 전달할 때, 새로 객체를 생성해 보내지 말고 state 그대로 넘기고, 필요한 데이터 가공은 자식 컴포넌트 안에서 하자. props 값이 변경될 때마다 컴포넌트를 렌더링하므로 state만 전달해주고 자세한 연산은 자식 컴포넌트 안에서 하도록 하는게 좋다.
  5. map() 함수 사용시 컴포넌트의 key값으로 인덱스 값 넣지 않기. 배열 중간에 요소가 삽입 또는 수정, 삭제될 경우 그 이후의 요소들은 전부 인덱스가 변경되기 때문이다.

리액트 컴포넌트가 리렌더링하는 상황

  1. 전달받은 props가 변경될 때
  2. 자신의 state가 바뀔
  3. 부모 컴포넌트가 리렌더링될 때
  4. forceUpdate 함수가 실행될 때

컴포넌트 리렌더링 방지법

  1. class 형 컴포넌트: shouldComponentUpdate라는 라이프사이클 메서드 사용

  2. 함수 컴포넌트: export 할 때 React.memo() 사용해 컴포넌트의 props가 바뀌지 않은 경우 리렌더링하지 않도록 설정

  3. setter 함수에 새로운 상태를 파라미터로 넣지 말고 상태 업데이트('->')를 어떻게 할지 정의하는 업데이트 함수를 넣기

[업데이트 전]

상태 업데이트 전

[업데이트 후]

상태 업데이트 후

  1. useReducer 사용 App.js 내(& 컴포넌트 밖)에 상태 업데이트 로직을 모아둘 수 있음.

[상태 업데이트 로직]

상태 업데이트 로직

useState 써보기

usestate 예시

function App() {
    const [text, setText] = useState('감추기');
    // 1

    const buttonClick = () => {
        text==='감추기'? setText("보이기") : setText("감추기")
    }
    // 2

    return (
        <div className="App">
            {text==='보이기' && <MainHeader text='hello'></MainHeader>}  
            <button onClick={buttonClick}>{text}</button>    
        </div>
    );
    //3
}
  1. useState(초기값), 리턴값은 배열로 [상태데이터, 상태 세터함수]
  2. 간결하게 쓴 if문이다!
  3. text==='보이기'에 and 연산을 함으로써 해당 조건에 맞으면 <MainHeader> 컴포넌트를 표시하도록 하였다.

변수 객체화

변수 간단하게 쓰기

이름의 성(lastname), 이름(first name)과 같이 거의 따로 쓰는 게 없을 때, 위의 코드보단
객체화해서 아래처럼 쓰는게 좋다.

const [name, setName] = useState({
    first: '하은',
    last: '박'
});

useRef()

  • input 관리할 때 유용한 함수다.
 return (
    <div className="App">
      <h1>{name.last}{name.first}</h1>
      <input name='성' placeholder='성'></input>
      <input name='이름' placeholder='이름'></input>
      <button onClick={confirm}>확인</button>
    </div>
  );

위와 같은 코드가 있다고 할때, input에 입력된 값을 저장하거나 받는 함수가 없다.
그럴 때 쓸 수 있는게 useRef() 함수다!

  const firstNameRef = useRef()
  const lastNameRef = useRef()

  const confirm = () => {
    // setName();
    console.log(firstNameRef.current.value)
  }

  return (
    <div className="App">
      <h1>{name.last}{name.first}</h1>
      <input name='성' placeholder='성' ref={lastNameRef}></input>
      <input name='이름' placeholder='이름' ref={firstNameRef}></input>
      <button onClick={confirm}>확인</button>
    </div>
  );

이런 식으로 <input> 태그 ref 속성에 useRef 함수를 넣어주면 그 안에 들어온 인풋값을 참조해올 수 있다.

useRef console

confirm()함수에서 firstNameRef.current.value 를 콘솔 찍어보니 input으로 받은 값이 나온다! 이벤트 함수에서 e.target.value와 비슷한 원리인 듯 하다.

useRef를 사용해 인풋 값을 화면에 띄우는 코드

function App() {
  const [name, setName] = useState({
    first: '하은',
    last: '박'
  });

  const firstNameRef = useRef()
  const lastNameRef = useRef()

  const confirm = () => {
    setName({
      first: firstNameRef.current.value,
      last: lastNameRef.current.value
    })
  }

  return (
    <div className="App">
      <h1>{name.last}{name.first}</h1>
      <input name='성' placeholder='성' ref={lastNameRef}></input>
      <input name='이름' placeholder='이름' ref={firstNameRef}></input>
      <button onClick={confirm}>확인</button>
    </div>
  );
}

export default App;

useRef 함수로 참조해온 값을 setter 함수(setName)에서 바꿔주면 간단하게 완성된다!!