[React] Context API / useReducer

lim1313·2022년 1월 21일
0

TIL

목록 보기
8/22

🍊 Context API

context는 다양한 레벨에 네스팅된 많은 컴포넌트에게 데이터를 전달하는 것이다.

context를 이용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다.

일반적인 React 데이터는 위에서 아래로 (즉, 부모로부터 자식에게) props를 통해 전달되지만, 여러 컴포넌트들에 전해줘야 하는 props의 경우 이 과정이 번거로울 수 있다. context를 이용하면, 단계마다 props를 넘겨주지 않아도 많은 컴포넌트가 이러한 값을 공유할 수 있다.

하지만, context를 사용하면 컴포넌트를 재사용하기가 어려워지므로 꼭 필요할 때만 사용해야 한다.

📌 React.createContext

Context 객체를 만든다.

const MyContext = React.createContext(defaultValue);

📌 context.Provider

Context 오브젝트에 포함된 React 컴포넌트인 Provider는 context를 구독하는 컴포넌트들에게 context의 변화를 알리는 역할을 한다.

Provider 컴포넌트는 value prop을 받아서 이 값을 하위에 있는 컴포넌트에게 전달한다. 값을 전달받을 수 있는 컴포넌트의 수에 제한은 없다. Provider 하위에 또 다른 Provider를 배치하는 것도 가능하며, 이 경우 하위 Provider의 값이 우선시된다.

Provider 하위에서 context를 구독하는 모든 컴포넌트는 Provider의 value prop가 바뀔 때마다 다시 렌더링 된다

<MyContext.Provider value={{list, todolist, loading}}>

📌 Context.Consumer

context 변화를 구독하는 React 컴포넌트
이 컴포넌트를 사용하면 함수 컴포넌트안에서 context를 구독할 수 있다.

이 함수는 context의 현재값을 받고 React 노드를 반환한다. 이 함수가 받는 value 매개변수 값은 해당 context의 Provider 중 상위 트리에서 가장 가까운 Provider의 value prop과 동일하다. 상위에 Provider가 없다면 value 매개변수 값은 createContext()에 보냈던 defaultValue와 동일할 것이다.

function TodoList(props) {
  return <TodoContext.Consumer>
    	    {(value) => value.list}
	 </TodoContext.Consumer>;
}

📌 useContext

context 객체(React.createContext에서 반환된 값)을 받아 그 context의 현재 값을 반환한다. context의 현재 값은 트리 안에서 이 Hook을 호출하는 컴포넌트에 가장 가까이에 있는 <MyContext.Provider>의 value prop에 의해 결정된다.

import {TodoContext} from './App.js'

function TodoList(props) {
  const { list } = useContext(TodoContext);

  return <div>{list}</div>;
}

📌 렌더링 문제

다시 렌더링할지 여부를 정할 때 참조(reference)를 확인하기 때문에, Provider의 부모가 렌더링 될 때마다 불필요하게 하위 컴포넌트가 다시 렌더링 되는 문제가 생길 수도 있다. 예를 들어 아래 코드는 value가 바뀔 때마다 매번 새로운 객체가 생성되므로 Provider가 렌더링 될 때마다 그 하위에서 구독하고 있는 컴포넌트 모두가 다시 렌더링 될 것입니다.

class App extends React.Component {
  render() {
    return (
      <MyContext.Provider value={{something: 'something'}}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}

이를 피하기 위해서는 값을 부모의 state로 끌어올리는 방법이 있다.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'},
    };
  }

  render() {
    return (
      <MyContext.Provider value={this.state.value}>
        <Toolbar />
      </MyContext.Provider>
    );
  }
}

🍊 useReducer

상태를 업데이트 할 때에는 useState 를 사용해서 새로운 상태를 설정었는데, 상태를 관리하게 될 때 useReducer를 사용할 수 있다.
이 Hook 함수를 사용하면 컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있다. 상태 업데이트 로직을 컴포넌트 바깥에 작성 할 수도 있고, 혹은 다른 파일에 작성 후 불러와서 사용 할 수도 있다.

const initial = ['run', 'study'];

function reducer(state, action) {
  switch (action.type) {
    case 'ADD_LIST':
      return [...state, action.payload];
    default:
      return state;
  }
}

function App(props) {
  const [state, dispatch] = useReducer(reducer, initial);

  return (
    <TodoContext.Provider value={{ state, dispatch }}>
      <TodoList />
    </TodoContext.Provider>
  );
}

TodoLi 파일 중 dispatch에 atction 전달

  const addClick = () => {
    dispatch({ type: 'ADD_LIST', payload: inputRef.current.value });
  };

참고자료

React 공식문서

profile
start coding

0개의 댓글