React Context

Dev_Sumni·2022년 6월 3일
0
post-thumbnail

전역상태관리 Context

  • 전역상태관리 미사용
    props를 통해 가지고있는 state를 다른 컴포넌트에 내려준다
    (다른 컴포넌트에게 전달하기 위해 여러차례 props를 전달해야함 (props drilling))

  • 전역상태관리 사용
    전역상태를 하나 두고(ex.store) 그곳에 업데이트 하면 다른 컴포넌트들이 state를 내려다 사용한다
    (store는 여러개가 될 수도 있음)

  • 단점: 컴포넌트 재사용, 유닛테스트 작성이 어려움

컴포넌트 합성

  • 컴포넌트 안에서 다른 컴포넌트를 가져다 쓰는 패턴
    props drilling을 해결하기 위해 컴포넌트 합성을 사용하는것이 좋을 수 있다

  • 컴포넌트 합성을 통해 해결한 경우
    Inversion of control이 발생한다

컴포넌트가 re-render 되는 조건 생각해보기

let name = ''; 
const Hello1 = () => ( 
  <div> 
    this is Hello1. and Name is {name} 
    <Hello2 /> 
  </div> 
); 
const Hello2 = () => ( 
  <div> 
    this is Hello2. and Name is {name} 
    <Hello3 /> 
  </div> 
); 
const Hello3 = () => ( 
  <div> 
    this is Hello3. and Name is {name} 
    <Hello4 /> 
  </div> 
);   
     
const Hello4 = () => ( 
  <div> 
    this is Hello4. 
    <div>Hello {name}!</div> 
  </div> 
);   
 
const App = () => {
  const handleClickButton = () => {
    name = 'asdf';
  }
  
  return (
    <> 
      <Hello />
      <button onClick = {handleClickButton}>click me!</button>
    </>
  );
}

const App = () => {
  const [uselessState, setUselessState] = React.useState(false);
  const handleClickButton = () => {
    name = 'asdf';
    setUselessState(true);
  }
  • asdf 전역 변수 값이 바뀌었을때, state를 업데이트 함으로써 부모 컴포넌트를 리렌더 함

react context

  • 전역 상태의 업데이트를 감지할 수 있도록 react에서 제공하는 API(context) 사용
import { createContext, useContext } from "react"; 

const defaultName = 'asdf'; 
const NameContext = createContext(defaultName); 
     
const Hello1 = () => { 
  const name = useContext(NameContext); 
  return ( 
    <div> 
      this is Hello1. and Name is {name} 
      <Hello4 /> 
    </div> 
  ); 
}; 
const Hello4 = () => { 
  const name = useContext(NameContext); 
  return ( 
    <div> 
      this is Hello4 
      <div>Hello {name}!</div> 
    </div> 
  ); 
}; 
const App = () => ( 
  <NameContext.Provider value={defaultName} > 
    <Hello1 /> 
  </NameContext.Provider> 
); 
export default App;
  • createContext에서 context 하나 만들어 두고(NameContext), context에 있는 Provider라는 컴포넌트로 부모에 렌더하면 자식 컴포넌트에서는 useContext라는 API 통해서 context로 부터 값을 꺼내올 수 있다
    (useContext를 사용하기 위해서는 부모가 Provider를 렌더하고 있어야 함)

🚩 App component를 수정하여 context의 value를 update 했을 때 Hello1, Hello4 컴포넌트가 re-render 되는지 확인하기

import { createContext, useContext } from "react"; 

const defaultName = 'asdf'; 
const NameContext = createContext(defaultName); 
     
const Hello1 = () => { 
  const name = useContext(NameContext); 
  return ( 
    <div> 
      this is Hello1. and Name is {name} 
      <Hello4 /> 
    </div> 
  ); 
}; 
const Hello4 = () => { 
  const name = useContext(NameContext); 
  return ( 
    <div> 
      this is Hello4 
      <div>Hello {name}!</div> 
    </div> 
  ); 
}; 
const App = () => ( 
  <NameContext.Provider value={defaultName} > 
    <Hello1 /> 
  </NameContext.Provider> 
); 
export default App;

import React, { useState, createContext, useContext } from "react";

const NameContext = createContext('');
const Hello1 = () => {
  const name = useContext(NameContext);
  const hello4 = React.useMemo(() => {
    console.log('re-render in hello1');
    return <Hello4 />
  }, []);
  return (
    <div>
      this is Hello1. and Name is {name} {hello4}
    </div>
  );
};
const Hello4 = () => {
  console.log('re-render in hello4');
  const name = useContext(NameContext);
  return (
    <div>
      this is Hello4. and Name is {name}
    </div>
  );
};

const App = () => {
  const [test, setTest] = useState('asdf');
  return (
    <>
      <input type="text" onChange={(e)=>setTest(e.target.value)} value={test} />
      <NameContext.Provider value={test} >
        <Hello1 />
      </NameContext.Provider>
    </>
  )
};

export default App

context api의 문제점

  • useContext로 watch중인 Context가 update되면 컴포넌트가 re-render됨

🚩 App component를 수정하여 context의 name을 업데이트한 경우 어떤 컴포넌트가 re-render되는지 확인하기

+문제점이 있다면 해결해서 구현해보기

import { createContext, useContext } from "react"; 

const defaultUser = { 
  name: 'jin', 
  id: 'woorung', 
}; 
const UserContext = createContext(defaultUser); 
const HelloName = () => { 
  const { name } = useContext(UserContext); 
  return ( 
    <div> 
      this is HelloName. and Name is {name} 
    </div> 
  ); 
}; 
const HelloId = () => { 
  const { id } = useContext(UserContext); 
  return ( 
    <div> 
      this is HelloId. and Id is {id} 
    </div> 
  ); 
}; 
// App.tsx 
const App = () => ( 
  <UserContext.Provider value={defaultUser} > 
    <HelloId /> 
    <HelloName /> 
  </UserContext.Provider> 
);

export default App;

const HelloName = () => { 
  const name = useContext(UserContext2); 
  return ( 
    <div> 
      this is HelloName. and Name is {name} 
    </div> 
  ); 
}; 
const HelloId = () => { 
  const id = useContext(Context1); 
  return ( 
    <div> 
      this is HelloId. and Id is {id} 
    </div> 
  ); 
}; 
// App.tsx 
const App = () => ( 
  <Context1.Provider value={defaultId}> 
    <Context2.Provider value={defaultName}> 
      <HelloId /> 
      <HelloName /> 
    <Context2.Provider> 
  <Context1.Provider> 
); 
export default App;
  • Context의 일부가 update 되는 경우 Context를 두개 만들기
profile
개발 일지 끄적 끄적,,

0개의 댓글

관련 채용 정보