
Redux를 React와 연동해서 사용하기 편리하도록 만든 공식적인 라이브러리이다.
Redux 는 독립적인 도구이다. React 역시 독립적인 도구이다. 한마디로 이 둘을 서로 연결하는 도구가 바로 React-redux 이다.
물론, 이전 글에서 포스트한 기본적인 Redux로 React에서 사용 가능하다.
하지만, React 관점에서 더 편하게 사용하기 위해 React-redux 를 사용한다.
공통점
store ➡️ component ➡️ action ➡️ dispatch ➡️ reducer ➡️ store 순서는 동일하다.

차이점
react-redux 는 store ➡️ component , component ➡️ action 단계에서 connect 라는 함수를 사용한다.
React-redux 에 중요한 4가지 요소가 있다.
state 를 '어떤 컴포넌트들에게 제공할 것인가?' 에 대한 가장 바깥쪽에서 알려주는 큰 울타리를 정의하는 컴포넌트이다.
Provider 의 Props 중에 store 를 반드시 정의해줘야 한다. 이름에서 알 수 있다시피 Redux 의 createStore 로 만든 store 를 집어 넣어 준다.
아래 예제를 보면 Provider 로 감싸진 ParentComponent 라는 이름의 컴포넌트는 store 가 가진 상태를 사용할 수 있다.
그렇다면 ParentComponent 의 하위 컴포넌트인 ChildComponent 역시 store 에 담긴 데이터를 사용할 수 있는 것이다.
import {SafeAreaView, Text, View} from 'react-native';
import {createStore} from 'redux';
import {Provider, useSelector, useDispatch, connect} from 'react-redux';
function App(): JSX.Element {
const reducer = (currentState: any, action: any) => {
if (!currentState) {
return {
number: 1,
};
}
const newState = {...currentState};
return newState;
};
const store = createStore(reducer);
return (
<Provider store={store}>
<ParentComponent />
</Provider>
);
}
const ParentComponent = () => {
return (
<SafeAreaView>
<ChildComponent />
</SafeAreaView>
);
};
const ChildComponent = () => {
const number = useSelector(state => state.number);
return (
<View>
<Text>{number}</Text>
</View>
);
};
export default App;
store 가 가지고 있는 상태들 중에 '어떤 상태를 가져다 쓸래?' 에 대한 역할을 담당한다.
사용 방법은 간단하다.
아래 예제와 같이 상태를 가져다 쓰고 싶은 컴포넌트 안에서 useSelector 를 호출한 후 어떤 state 를 가져다 쓸 것인지 return 해주면 된다.
const ChildComponent = () => {
const number = useSelector(state => state.number);
return (
<View>
<Text>{number}</Text>
</View>
);
};
❗️여기서 중요한 점은, 상위 컴포넌트인 ParentComponent 로 부터 props를 전달 받아 사용하는 것이 아니라, ChildComponent 에서 곧장 state 를 호출하여 사용했다는 점이다. 이는 Redux 에서 Props drilling 이슈와 관련된다.
action 을 통해 reducer 를 호출하여 state 를 변경하는 메소드이다.
다음 예제처럼 버튼을 클릭했을 때, number 가 +1 씩 증가하는 기능을 만들어보자.
const ChildComponent = () => {
const number = useSelector(state => state.number);
const dispatch = useDispatch();
return (
<View>
<Text>{number}</Text>
<Button
title="+"
onPress={() => {
dispatch({
type: 'INCREASE',
});
}}></Button>
</View>
);
};
useDispatch 메소드를 호출하고 그 안에 action 객체 타입을 넣는다.
버튼을 누르는 순간 dispatch 가 동작하게 되고, reducer 가 호출되된다. action 에서 호출한 type 에 맞게 조건문이 발동하면서 state 가 변경되고, 변경을 감지한 store 가 상태를 업데이트 하게 되며 최종적으로 number 는 +1 이 되어 화면에 나타난다.
const reducer = (currentState: any, action: any) => {
if (!currentState) {
return {
number: 1,
};
}
const newState = {...currentState};
if (action.type === 'INCREASE') {
newState.number++;
}
return newState;
};
🔔 참고
const newState = {...currentState} 에서 state 를 복사하는 이유는 '상태의 불변성 법칙' 때문에 그렇다.
React 또는 React Native 에서는 상태를 직접적으로 변경할 수 없다. 상태를 변경하기 위해선 원본을 복사하여 복사본을 수정한 후, 그 것을 원본과 비교하여 변경 된 부분만 상태를 업데이트하기 때문에 위 같은 코드가 들어간 것이다.
connect 는 ChildComponent 와 같이 하위 컴포넌트에서 store 에 접근하기 위해 사용되는 또 다른 메소드이다.
결론적으로, useSelector 와 useDispatch 가 워낙에 편하기 때문에 사실 사용 할 일이 별로 없다. 따라서 깊이 안들어가기 위해 따로 예제도 다루지 않겠다.