[React Native TIL] Context API(useContext)

cooking_123·2024년 3월 13일

React Native TIL

목록 보기
17/30

Context API를 이용하면 전역으로 상태를 관리해야 하는 상황에서 props를 일일이 전달하지 않아도 원하는 컴포넌트에서 해당 데이터를 이용할 수 있다.

1. createContext

컨텍스트 API를 사용할 때 가장 먼저 호출되는 함수는 createContext이다. 컨텍스트를 생성하는 함수로 파라미터의 기본값을 전달하고 createContext함수에 전달되는 기본 값은 적절한 provider을 찾지 못했을 떄 사용한는 값이다.

const Context = createContext(기본값)
  • Context API를 이용해서 자식 컴포넌트로 전달할 수 있는 데이터에는 단순히 값뿐만 아니라 함수도 전달할 수 있다.
import {createContext} from 'react';

const Context = createContext({
	name:'Beomjun',
  	setName: ()=>{}
})

2. Provider, Consumer

2-1. Provider 컴포넌트

Provider 컴포넌트의 역할은 context의 변화를 하위 컴포넌트들에게 알리는 역할이다. React Native에서 ThemProvider 컴포넌트도 Context ApI의 Provider 컴포넌트이다.

  • Provider 컴포넌트를 이용해서 value 속성의 데이터를 지정하면 하위 컴포넌트로 해당 데이터를 전달할 수 있다.
<Provider value={}>
 ...
</Provider>

2-2. Consumer 컴포넌트

Consumer 컴포넌트의 역할은 부모 컴포넌트 중에서 가장 가까이 있는 Provider 컴포넌트가 전달하는 데이터를 받아서 이용하는 역할이다.

  • Consumer 컴포넌트를 사용할떄는 자식이 함수여야 한다. Consumer 컨포넌트로 전달된 데이터는 자식으로 설정된 함수의 파라미터로 전달된다.
<Consumer>
  {value=> ...}  
</Consumer>
  • Consumer컨포넌트는 provider 컨포넌트가 전달해주는 데이터를 이용하기에 provider 컴포넌트의 자식 컴포넌트로 사용되어야 한다.
<Provider value={}>
	 <Consumer>
	</Consumer>
</Provider>
  • Consumer컨포넌트는 부모 컨포넌트 중 가장 가까이에 있는 provider 컴포넌트로부터 데이터를 전달 받아 사용하기에
<Provider1 value={}>
	 <Consumer1> // => Consumer1은 Provider1이 제공하는 데이터 이용
  		<Provider2 value={}>
	 		<Consumer2>// => Consumer2은 Provider2이 제공하는 데이터 이용
			</Consumer2>
		</Provider2>
	</Consumer1>
</Provider1>

예시 코드

import React, { createContext } from 'react';
...
const App2 = () => {
    //사용자의 정보를 관리하는 context 제작. 기본 값은 객체 형태
    const UserContext = createContext({ name: 'gyduddl' });
    return (
        // 기본값으로 설정된 데이터의 모양(key값이 같아야 하는듯)과 
      	//provider value로 설정된 모양이 일치해야 한다.
        <UserContext.Provider value={{ name: 'gyduddl kim' }}>
            <Container>
                {/* //consumer 컴포넌트를 이용해 comsumer 컴포넌트의 자식으로 데이터 전달 */}
                <UserContext.Consumer>
      			{(value) => <StyledText>{value.name}</StyledText>}//=>출력'gyduddl kim'
				</UserContext.Consumer>
                <UserContext.Provider value={{ name: 'gyduddl222' }}>
                    <UserContext.Consumer>
                  {(value) => <StyledText>{value.name}</StyledText>} //=>출력 : 'gyduddl222'
				</UserContext.Consumer>
                </UserContext.Provider>
            </Container>
        </UserContext.Provider>
    );
};
  • 만약 consumer 컴포넌트가 이용할 provider 컴포넌트를 찾을 수 없다면 createContext의 파라미터로 전달된 기본 값을 이용하게 된다.
const Context = createContext(기본값)

<Consumer>
</Consumer>

4. useContext

Hook 중에서 useContext를 이용하면 Context API를 더 편하게 이용할 수 있다. useContext를 이용하면 Provider 컴포넌트가 전달하는 데이터를 굳이 Consumer 컴포넌트를 이용하지 않더라도 Context를 받아와서 사용할 수 있다.

const 데이터 = useContext(Context)

5. 실습

5-1. Provider, consumer을 하나의 파일로 관리

//contexts/User.js
import React, { createContext, useState } from 'react';

//createContext를 이용해서 context를 만듬
const UserContext = createContext({
    name: '',
    setName: () => {},
});

//매번 context에 provider을 접근해서 사용하지 않도록
//userProvider 컴포넌트 만듬
const UserProvider = ({ children }) => {
    //사용자의 이름을 관리하는 상태 변수(기본값설정)
    const [name, setName] = useState('gyduddl');
    //povider의 value로 설정할 value는 name과 setName을 갖고 있도록 설정
    const value = { name, setName };
    //provider 컴포넌트의 자식 컴포넌트로 들어오는 컴포넌트들을 children을 이용해서 렌더링
    return <UserContext.Provider value={value}>{children}</UserContext.Provider>;
};

const UserConsumer = UserContext.Consumer;

//외부에서도 사용할 수 있도록 export
export { UserProvider, UserConsumer };

export default UserContext;

5-2. 유저 정보를 렌더링하고 변경할 수 있는 컴포넌트 제작

//components/User.js
import React from 'react';
import styled from 'styled-components/native';
import { UserConsumer } from '../contexts/User';

const StyledText = styled.Text`
    font-size: 30px;
    font-weight: 600;
`;

const User = () =>{
    return(
        <UserConsumer>
            {({name})=> <StyledText>Name:{name}</StyledText>}
        </UserConsumer>
    )
}

export default User;

5-3. Input 창 추가해서 상태값 변경하기

//components/User.js
import React, { useState } from 'react';
import styled from 'styled-components/native';
import { UserConsumer } from '../contexts/User';

const StyledText = styled.Text`
    font-size: 30px;
    font-weight: 600;
`;

const StyledInput = styled.TextInput`
    border: 1px solid #111111;
    font-size: 26px;
    padding: 10px;
    width: 100%;
`;

const User = () => {
    const [text, setText] = useState('');
    return (
        <>
        {/* 버전 1.  */}
            {/* <UserConsumer>{({ name }) => <StyledText>Name:{name}</StyledText>}</UserConsumer>
            <UserConsumer>
                {({ setName }) => (
                    <StyledInput
                        value={text}
                        onChangeText={setText}
                        onSubmitEditing={() => {
                            setName(text);
                            setText('');
                        }}
                    />
                )}
            </UserConsumer> */}
            {/* 버전 2.  */}
            <UserConsumer>
                {({ name, setName }) => (
                    <>
                        <StyledText>Name:{name}</StyledText>
                        <StyledInput
                            value={text}
                            onChangeText={setText}
                            onSubmitEditing={() => {
                                setName(text);
                                setText('');
                            }}
                        />
                    </>
                )}
            </UserConsumer>
        </>
    );
};

export default User;

5-4. useContext를 이용해서 Consumer 사용하지 않고 코드 줄이기

//components/User.js
import React, { useState, useContext } from 'react';
import styled from 'styled-components/native';
import UserContext from '../contexts/User';

const StyledText = styled.Text`
    font-size: 30px;
    font-weight: 600;
`;

const StyledInput = styled.TextInput`
    border: 1px solid #111111;
    font-size: 26px;
    padding: 10px;
    width: 100%;
`;

const User = () => {
    const [text, setText] = useState('');
    //useContext를 이용해서 데이터를 받아오는데 useContext에 전달되어야 되는 값은
    //provider이나 consumer이 아닌 context 자체가 전달되어야 한다.
    const { name, setName } = useContext(UserContext);
    return (
        <>
            <StyledText>Name:{name}</StyledText>
            <StyledInput
                value={text}
                onChangeText={setText}
                onSubmitEditing={() => {
                    setName(text);
                    setText('');
                }}
            />
        </>
    );
};

export default User;

후기...

확실히 useContext 를 사용하여 Consumer을 사용하지 않고 상태관리를 하니 코드가 훨씬 직곤적이고 사용하기 편해졌다.

0개의 댓글