부모에게서 데이터를 전달 받을 때, 멀리 떨어져있어 여러 컴포넌트를 거쳐야한다면 상당히 번거롭다. 이 때 Context API를 사용하여 Context를 생성해 필요한 컴포넌트에서 데이터를 바로 받아올 수 있다.
Context를 생성하는 createContext함는 파라미터에 생성되는 Context의 기본값을 지정할 수 있다.
생성된 Context 오브젝트는 입력된 기본값 외에도 Consumer컴포넌트와 Provider컴포넌트를 갖고 있다. Consumer 컴포넌트는 상위 컴포넌트 중 가장 가까운 곳에 있는 Provider컴포넌트가 전달하는 데이터를 이용한다. 상위에 Provider가 없다면 기본값을 사용한다.
Consumer 컴포넌트의 자식은 반드시 리액트 컴포넌트를 반환하는 함수여야 하고, Context의 현재값을 파라미터로 전달받아 사용할 수 있다.
const User = () => {
return (
<UserContext.Provider value={{ name: 'React Native' }}>
<UserContext.Consumer>
{value => <StyledText>Name: {value.name}</StyledText>}
</UserContext.Consumer>
</UserContext.Provider>
);
};
Context에 있는 Provider컴포넌트른 하위 컴포넌트에 변화를 알리는 역할을 한다. 하위 컴포넌트는 Provider의 값이 변경될때마다 렌더링을 다시 한다.
const App = () => {
return (
<UserContext.Provider value={{ name: 'Dayeon' }}>
<Container>
<User />
</Container>
</UserContext.Provider>
);
};
User 컴포넌트는 Provider로 감싸져 Context의 기본값을 사용하지 않는다. Provider 컴포넌트가 전달하는 데이터를 사용하며, 데이터가 없을 땐 Provider에 값을 직접 넣어준다.
Consumer 컴포넌트는 가장 가까운 Provider에서 값을 받으므로 중간에 다른 Provider가 있다면 그 아래 자식은 다른 Provider에서 값을 받아 사용한다.
import React, { useState, useContext } from 'react';
import styled from 'styled-components/native';
import UserContext, { UserConsumer } from '../contexts/User';
const StyledInput = styled.TextInput`
border: 1px solid #606060;
width: 250px;
padding: 10px 15px;
margin: 10px;
font-size: 24px;
`;
const Input = () => {
const [name, setName] = useState('');
return (
<UserConsumer>
{({ dispatch}) => {
return (
<StyledInput
value={name}
onChangeText={text => setName(text)}
onSubmitEditing={() => {
dispatch(name);
setName('');
}}
placeholder="Enter a name..."
autoCapitalize="none"
autoCorrect={false}
returnKeyType="done"
/>
); }}
</UserConsumer>
);
};
export default Input;
useContext(UserContext)로 현재 컨텍스트에서 dispatch를 꺼낸다. 사용자가 텍스트 입력하면 name 상태에 저장된다. 엔터(완료) 누르면 dispatch(name)을 호출해서 Context 안의 state를 변경한다. 그 후 setName('')으로 입력창을 비워준다.
Consumer 컴포넌트를 사용하지 않고 Context의 내용을 사용할 수 있게 해준다.
...
const { dispatch } = useContext(UserContext);
return (
<StyledInput
value={name}
onChangeText={text => setName(text)}
onSubmitEditing={() => {
dispatch(name);
setName('');
}}
placeholder="Enter a name..."
autoCapitalize="none"
autoCorrect={false}
returnKeyType="done"
/>
);
};