ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ReactJS] React state 관리
    웹 개발/ReactJS 2021. 5. 14. 21:40
    반응형


    일반 변수는 변수값이 변해도 새롭게 렌더링 되지 않는다.

    let count = 1;


    이를 해결하기 위해 state를 관리하여 DOM을 업데이트 하는 react hook들을 정리해보려 한다.


    useState

    데이터 공간 생성
    const [데이터, 데이터변경함수] = useState(초기데이터);

    ex)

    const [count, setCount] = useState(0); .. <span onclick = {()=>{setCount(count+1)}>

    -> onclick 이벤트를 통해 useState의 변수값이 바뀌면 컴포넌트가 새롭게 렌더링 된다.
    이 때 랜더링마다 count 값을 업데이트 되는 것이 아니라 랜더링을 통해 새롭게 생성된 독립적인 상수를 보는 원리이다.

    ** Immutability

    react는 useState의 변수를 직접 바꾸지 않고 deep copy를 통해 state를 변경하는 것을 권장한다.
    state를 직접 변경하게 되면 특정 객체가 변경되었을 때 이 객체를 참조하고 있던 객체에서도 변경이 일어난다.
    하지만 deep copy를 통해 변경이 일어난 객체의 프로퍼티만 비교함으로써 React에서 최적화가 가능하다.

    const [count, setCount] = useState(0); function changeCount(){ var newCount = [..count]; newCount = count +1; setCount(newCount); } <span onclick = {()=>{changeCount()}>

    Immutability
    객체가 생성된 이후 그 상태를 변경할 수 없는 디자인 패턴


    useRef

    특정 DOM 선택

    ex)
    - useRef() 를 사용해 Ref 객체 생성

    const nameInput = useRef(); 

    - 선택하고 싶은 DOM 에 ref 값으로 설정

     <input name="name" placeholder="이름" onChange={onChange} value={name} ref={nameInput} />


    - Ref 객체의 .current 값은 우리가 원하는 DOM 을 가르키게 된다.

     nameInput.current.focus();


    - 전체 코드

    import React, { useState, useRef } from 'react'; const nameInput = useRef(); const onReset = () => { setInputs({ name: '', nickname: '' }); nameInput.current.focus(); }; ... <input name="name" placeholder="이름" onChange={onChange} value={name} ref={nameInput} />

    useEffect


    각각의 이펙트 버전은 매번 랜더링에 랜더링에 속한 props와 state를 본다.
    이전 이펙트는 새 prop과 함께 리랜더링 되고 난 뒤에 클린업된다.
    이펙트의 클린업은 “최신” prop을 읽는 것이 아니라 클린업이 정의된 시점의 랜더링에 있던 값을 읽는 것입니다.

    리액트가 {id: 20} 을 가지고 UI를 랜더링한다. 브라우저가 실제 그리기를 한다.
    화면 상에서 {id: 20} 이 반영된 UI를 볼 수 있다.
    리액트는 {id: 10} 에 대한 이펙트를 클린업한다.
    리액트가 {id: 20} 에 대한 이펙트를 실행한다.

    -> 리액트는 DOM과 함께 리액트 트리 바깥에 있는 것들을 props와 state에 따라 동기화 할 수 있게 한다.

    특정한 이펙트가 불필요하게 다시 실행되는 것을 방지하고 싶다면 의존성 배열을(“deps” 라고 알려진 녀석이죠) useEffect 의 인자로 전달할 수 있는 것입니다.
    첫 번째 요소 : 함수
    두 번째 요소 : 의존값이 들어있는 배열 (deps)

    - 컴포넌트가 마운트 됐을 때 (처음 나타났을 때),
    - 언마운트 됐을 때 (사라질 때),
    - 업데이트 될 때 (특정 props가 바뀔 때)

    - deps가 비어있을 때 : 컴포넌트가 마운트 됐을 때만 불러옴

     useEffect(() => { console.log('컴포넌트가 화면에 나타남'); return () => { console.log('컴포넌트가 화면에서 사라짐'); }; }, []);

    - deps 값이 있을 때 : deps 값이 언마운트시, 값이 바뀌기 직전에도 호출이 됩니다.

    useEffect(() => { console.log('user 값이 설정됨'); console.log(user); return () => { console.log('user 가 바뀌기 전..'); console.log(user); }; }, [user]);


    https://rinae.dev/posts/a-complete-guide-to-useeffect-ko#tldr-too-long-didnt-read---%EC%9A%94%EC%95%BD

    useMemo

    특정 함수로 연산값 재 사용 -> 랜더링 시 함수가 또 호출되는 것을 방지

     const count = useMemo(() => countActiveUsers(users), [users]); 

    useCallback

    useCallback 은 특정 함수를 새로 만들지 않고 재사용

     const onCreate = useCallback(() => { const user = { id: nextId.current, username, email }; setUsers(users.concat(user)); setInputs({ username: '', email: '' }); nextId.current += 1; }, [users, username, email]);

    React.memo

    리랜더링이 필요한 상황에만 리랜더링할 수 있도록 함

    const CreateUser = ({ username, email, onChange, onCreate }) => { return ( <div> <input name="username" placeholder="계정명" onChange={onChange} value={username} /> <input name="email" placeholder="이메일" onChange={onChange} value={email} /> <button onClick={onCreate}>등록</button> </div> ); }; export default React.memo(CreateUser);

    useReducer

    useState와 유사한 기능으로 상태관리를 한다.
    - useReducer는 컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리해서 관리할 수 있음
    - reducer 는 현재 상태와 액션 객체를 파라미터로 받아와서 새로운 상태를 반환해주는 함수

    function reducer(state, action) { // 새로운 상태를 만드는 로직 // const nextState = ... return nextState; }

    - 컴포넌트가 관리하는 상태값이 여러개일때 용이

    const [state, dispatch] = useReducer(reducer, initialState); 


    - state : 우리가 앞으로 컴포넌트에서 사용 할 수 있는 상태
    - dispatch : 액션을 발생시키는 함수

    - 첫번 째 파라미터 : reducer 함수
    - 두번째 파라미터 : 초기 상태

    예시

    import React, { useReducer } from 'react'; 

    reducer 함수

    function reducer(state, action) { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state; } }
    function Counter() { const [number, dispatch] = useReducer(reducer, 0); const onIncrease = () => { dispatch({ type: 'INCREMENT' }); }; const onDecrease = () => { dispatch({ type: 'DECREMENT' }); };


    https://estaid.dev/reasons-to-maintain-immutability-with-react/
    https://rinae.dev/posts/a-complete-guide-to-useeffect-ko

    반응형

    댓글

Designed by Tistory.