[React] useContext()

dhbyun·2021년 8월 13일
0

React js

목록 보기
8/11
post-thumbnail

useContext()

React Hooks API

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

컴포넌트에서 가장 가까운 <MyContext.Provider>가 갱신되면 이 Hook은 그 MyContext provider에게 전달된 가장 최신의 context value를 사용하여 렌더러를 트리거 합니다. 상위 컴포넌트에서 React.memo 또는 shouldComponentUpdate를 사용하더라도 useContext를 사용하고 있는 컴포넌트 자체에서부터 다시 렌더링됩니다.

useContext로 전달한 인자는 context 객체 그 자체이어야 함을 잊지 마세요.

  • 맞는 사용: useContext(MyContext)
  • 틀린 사용: useContext(MyContext.Consumer)
  • 틀린 사용: useContext(MyContext.Provider)

useContext를 호출한 컴포넌트는 context 값이 변경되면 항상 리렌더링 될 것입니다. 만약 컴포넌트를 리렌더링 하는 것에 비용이 많이 든다면, 메모이제이션을 사용하여 최적화할 수 있습니다.


Testing

구성


Testing은 간단하게 2가지를 진행했습니다.

  • Context가 다른 2개의 하위 컴포넌트
    [StoreInput, Storeoutput, SecondStoreInput, SecondStoreOutput]
    (각각의 Context1개의 state를 갖게 됨)
  • Context가 같은 2개의 하위 컴포넌트
    [SecondStoreInput, SecondStoreInput2, SecondStoreOutput, SecondStoreOutput2]
    (하나 Context2개의 state를 갖게 됨)

Code

UseContextStore.js

import React, {useState, createContext} from 'react';

export const Store = createContext(null);

export const SecondStore = createContext(null);

export function UseContextStore({children}) {

    const [input, setInput] = useState('');

    const storeValue = {
        input, setInput
    }

    return (
        <Store.Provider value={storeValue}>
            {children}
        </Store.Provider>
    );
}

export function UseContextSecondStore({children}) {

    const [input1, setInput1] = useState('');

    // 하나의 Context에 두개의 값이 존재할 경우
    // const [input2, setInput2] = useState('');

    const storeValue = {
        input1, setInput1,

        // 하나의 Context에 두개의 값이 존재할 경우
        // input2, setInput2
    }

    return (
        <SecondStore.Provider value={storeValue}>
            {children}
        </SecondStore.Provider>
    );
}

UseContextApp.js

import React from 'react';

import {UseContextStore, UseContextSecondStore} from "./useContext_store/UseContextStore";

import ChildInput from "./ChildInput";
import ChildOutput from "./ChildOutput";


function UseContextApp(props) {
    return (
        <UseContextStore>
            <UseContextSecondStore>
                <div>
                    <ChildInput/>
                    <ChildOutput/>
                </div>
            </UseContextSecondStore>
        </UseContextStore>
    );
}

export default UseContextApp;

ChildInput.js

import React from 'react';

import StoreInput from "./StoreInput";
import SecondStoreInput from "./SecondStoreInput";

// 하나의 Context에 두개의 값이 존재할 경우
// import SecondStoreInput2 from "./SecondStoreInput2";

function ChildInput(props) {
    return (
        <div>
            {console.log('ChildInput render')}
            <p><b>StoreInput</b></p>
            <StoreInput/>
            <p><b>SecondStoreInput</b></p>
            <SecondStoreInput/>

            {/*하나의 Context에 두개의 값이 존재할 경우*/}
            {/*<p><b>SecondStoreInput2</b></p>*/}
            {/*<SecondStoreInput2/>*/}
        </div>
    );
}

export default ChildInput;

StoreInput.js

import React, {useContext} from 'react';

import {Store} from "./useContext_store/UseContextStore";

function StoreInput(props) {

    const { input, setInput } = useContext(Store);

    const InputOnChange = (event) => {
        setInput(event.target.value);
    }

    return (
        <div>
            {console.log('StoreInput render')}
            <input type="text" value={input} onChange={InputOnChange}/>
        </div>
    );
}

export default StoreInput;

SecondStoreInput.js

import React, {useContext} from 'react';

import {SecondStore} from "./useContext_store/UseContextStore";

function SecondStoreInput(props) {

    const { input1, setInput1 } = useContext(SecondStore);

    const InputOnChange = (event) => {
        setInput1(event.target.value);
    }

    return (
        <div>
            {console.log('SecondStoreInput render')}
            <input type="text" value={input1} onChange={InputOnChange}/>
        </div>
    );
}

export default SecondStoreInput;

ChildOutput.js

import React from 'react';

import StoreOutput from "./StoreOutput";
import SecondStoreOutput from "./SecondStoreOutput";

// 하나의 Context에 두개의 값이 존재할 경우
// import SecondStoreOutput2 from "./SecondStoreOutput2";

function ChildOutput(props) {
    return (
        <div>
            {console.log('ChildOutput render')}
            <StoreOutput/>
            <SecondStoreOutput/>

            {/*하나의 Context에 두개의 값이 존재할 경우*/}
            {/*<SecondStoreOutput2/>*/}
        </div>
    );
}

export default ChildOutput;

StoreOutput.js

import React, { useContext } from 'react';

import {Store} from "./useContext_store/UseContextStore";

function StoreOutput(props) {

    const { input } = useContext(Store);

    return (
        <div>
            {console.log('StoreOutput render')}
            <p>{input}</p>
        </div>
    );
}

export default StoreOutput;

SecondStoreOutput.js

import React, { useContext } from 'react';

import {SecondStore} from "./useContext_store/UseContextStore";

function SecondStoreOutput(props) {

    const { input1 } = useContext(SecondStore);

    return (
        <div>
            {console.log('SecondStoreOutput render')}
            <p>{input1}</p>
        </div>
    );
}

export default SecondStoreOutput;

SecondStoreInput2.js

import React, {useContext} from 'react';

import {SecondStore} from "./useContext_store/UseContextStore";

function SecondStoreInput2(props) {

    const { input2, setInput2 } = useContext(SecondStore);

    const InputOnChange = (event) => {
        setInput2(event.target.value);
    }

    return (
        <div>
            {console.log('SecondStoreInput2 render')}
            <input type="text" value={input2} onChange={InputOnChange}/>
        </div>
    );
}

export default SecondStoreInput2;

SecondStoreOutput2.js

import React, { useContext } from 'react';

import {SecondStore} from "./useContext_store/UseContextStore";

function SecondStoreOutput2(props) {

    const { input2 } = useContext(SecondStore);

    return (
        <div>
            {console.log('SecondStoreOutput2 render')}
            <p>{input2}</p>
        </div>
    );
}

export default SecondStoreOutput2;

Testing 결과

Testing 화면

  • 각각 입력을 하게 될 경우 하단에 입력된 값이 출력됨

Context가 다른 2개의 하위 컴포넌트
[StoreInput, Storeoutput, SecondStoreInput, SecondStoreOutput]
(각각의 Context는 1개의 state를 갖게 됨)

  • Store, SecondStore 각각의 Context가 변경되는 상황에만 렌더링 진행

Context가 같은 2개의 하위 컴포넌트
[SecondStoreInput, SecondStoreInput2, SecondStoreOutput, SecondStoreOutput2]
(하나 Context에 2개의 state를 갖게 됨)

  • 같은 Context를 사용할 경우 미사용 state가 변경될 경우에도 렌더링이 진행

마무리

React Hooks에서 지원하는 useContext()를 이용하게 되면 props를 이용하여 값을 전달하는 과정이 불필요하며, 하위 Component가 렌더링된다 하여도 Context를 미사용한 상위 Component는 렌더링이 진행되지 않게 됩니다.
Redux를 이용하는 것처럼 React 전역에서 Component간 값 전달 과정없이 사용할 수 있는 편리함을 제공하며, 불필요하게 렌더링되는 것을 방지할 수 있습니다. 하지만 하나의 Context만 사용할 경우 불필요한 렌더링이 발생할 수 있어 데이터간의 관계를 잘 생각하여 Context를 구현해야합니다.
감사합니다.

profile
어제보다 더 발전하는 오늘

0개의 댓글