react-redux는 React에서 redux를 편리하게 사용하게 해주는 뷰 바인딩 도구, 즉, 스토어를 뷰에 쉽게 연결 해주는 도구임.
핵심은
Provider
- 컴포넌트에서 리덕스를 사용하도록 서비스를 제공해줌
- Provider 자체도 컴포넌트
import { Provider } from 'react-redux';
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
);
ReactDOM 렌더링 하는 index.js 에 추가하기.
하지만 아직 다른 컴포넌트에서 store에 접근할수 없음
그래서
connect([...options])
connect 함수를 사용하는데 이 함수는
옵션을 인수로 받고 전달받은 인수를 사용해서 컴포넌트를 redux에 연결하는 또 다른 함수 를 반환 함
Ex)
connect()(컴포넌트)
Count컴포넌트를 연결하려면
connect()(Count)
즉 반환 받은 그 또 다른 함수에 redux에 연결하고 싶은 컴포넌트를 인수로 전달하면 됨
연결된 후 redux와 연결되어 있는 새로운 컴포넌트가 반환됨. (원래의 컴포넌트에는 변화 X)
(store에 연결 된 새로운 컴포넌트 클래스가 반환됨. 옵션이 없으면 this.props.store 로 접근 가능)
connect 에 option들을 넣으면 안 넣을 때보다 접근하기가 깔끔해짐.
connect(
[mapStateToProps],
[mapDispatchToProps],
[mergeProps],
[options]
)
mapStateToProps, mapDispatchToProps, mergeProps 는 함수 형태의 파라미터
mapStateToProps 는 state를 파라미터로 가진 함수이고 state 를 props로 연결 해주는 함수
mapDispatchToProps 는 dispatch 를 파라미터로 가진 함수이고 dispatch한 함수를 props로 연결 해주는 함수
mergeProps는 state 와 dispatch 를 파라미터로 가진 함수, 두개 동시에 사용 할때 사용하는 함수
options 에는
{ [ pure = true ], [ withRef = false ] }
pure 는 기본적으로 true 로 설정되어 있는데 true 일때는 불필요한 업데이트 X
withRef 는 기본적으로 false 이고 true 일때는 리덕스에 연결된 컴포넌트를 Wrapped(?)에 담아서 getWrappedInstance() 를 통하여 접근할수 있게함
Smart Component 인 Counter에서 redux에 connect를 한다음에 redux 작업을 할건데
Counter.js 안에서
import Value from './Value';
import Control from './Control';
Value, Control 컴포넌트는 리덕스에 연결해 받은 값을
render() {
return(
<Value number={this.props.number}/>
<Control
onPlus={this.props.handleIncrement}
onSubtract={this.props.handleDecrement}
onRandomizeColor={this.setRandomColor}
/>
</div>
);
}
이런 식으로 전달해 줄 것이다. (예시만 보여준것)
connect를 사용하기 위해서
import { connect } from 'react-redux';
로 불러 오고
export default Counter;
보다 위쪽에
아까 connect에 들어가는 옵션들을 선언 해줄건데
const mapStateToProps = (state) => {
//state는 컴포넌트의 state가 아니라 파라메터 명이 state인것. 그리고 리덕스의 state를 칭하는것.
return {
number: state.counter.number,
color: state.ui.color
};
}
const mapDispatchToProps = (dispatch) => {
return {
handleIncrement: () => { dispatch(actions.increment())},
handleDecrement: () => { dispatch(actions.decrement())},
handleSetColor: (color) => { dispatch(actions.setColor(color))}
};
}
이런식으로.
그리고 객체 리턴 안에 어떠한 props가 state의 어떠한값과 연결될지 정한다.
추가할 props 를 선언하고 state의 안에 있는 값을 넣음
액션을 추가할때는
import * as actions from '../actions';
로 만든 actions 를 불러오고
각 action에 원하는 props를 만들어서 props 안에 해당 action을 하는 함수를 넣는다
그리고 mapDispatchToProps 를 더 쉽게 하는 방법이 있는데
import { connect, bindActionCreators } from 'react-redux';
를 불러와서
const mapDispatchToProps = (dispatch) => {
return bindActionCreators(actions, dispatch);
}
이렇게 리턴해주면 알아서 액션과 dispatch의 처리를 알아서 해준다. 파라메터까지.
단점은 액션의 function 이름 그대로 사용할수 밖에 없다는 점.
잘 사용하면 유용함.
이제, Counter를 redux로 연결할 차례
export default connect()(Counter);
아까 말했듯이 connect() 가 다른 함수를 반환하고
그 함수의 인자를 Counter로 넣으면 연결됨.
그리고 첫번째 소괄호() 안에 options를 넣지 않으면
Ex)
return(
<div>
<Value number={this.props.store.getState().counter.number}/>
<Control />
</div>
);
해야하는데 options를 이렇게
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
전달 해주면
return(
<div >
<Value number={this.props.number}/>
<Control />
</div>
);
이렇게만 적어도 된다.
그래서 액션들까지 다 redux와 연결해보면
return(
<div>
<Value number={this.props.number}/>
<Control
onPlus={this.props.handleIncrement}
onSubtract={this.props.handleDecrement}
/>
</div>
);
이런식으로 하면 된다.
number, onPlus, onSubtract, onRandomizeColor 들은 해당 컴포넌트 들의 prop들의 이름 이므로 본인이 정한대로 해야함.
이제 div의 color를 랜덤하게 바꿔 볼껀데,
그 동작을 하는 메소드가 없으므로 Counter 컴포넌트에 메소드를 작성한다
class Counter extends Component {
...
setRandomColor() {
const color = [
Math.floor((Math.random() * 55) + 200),
Math.floor((Math.random() * 55) + 200),
Math.floor((Math.random() * 55) + 200)
];
this.props.handleSetColor(color);
}
...
}
this.props.handleSetColor(color);
에서 this를 사용하므로
this 를 바인딩 해줘야 하는데
보통 클래스 안의 맨 첫라인에
constructor(props) {
super(props);
this.setRandomColor1 = this.setRandomColor.bind(this);
}
를 넣어 this 를 바인딩 해준다.
( this.setRandomColor = this.setRandomColor.bind(this); 로 해도 되지만
본인은 기초 지식이 부족해 헷갈릴 때를 대비해 조금 변경하였다)
return(
<div>
<Value number={this.props.number}/>
<Control
onPlus={this.props.handleIncrement}
onSubtract={this.props.handleDecrement}
onRandomizeColor={this.setRandomColor1}
/>
</div>
);
그리고 onRandomizeColor 에 바인딩 된 this.setRandomColor1 을 넣는다.
또한, 그 색상을 위의 div의 style로 넣어 변경해보겠다.
smart component 는 보통 style이 없다고 하지만 예외적으로 그냥 넣는다.
render() {
const color = this.props.color;
const style = {
background: `rgb(${color[0]}, ${color[1]}, ${color[2]})`
};
return(
<div style={style}>
<Value number={this.props.number}/>
<Control
onPlus={this.props.handleIncrement}
onSubtract={this.props.handleDecrement}
onRandomizeColor={this.setRandomColor1}
/>
</div>
);
}
style 상수를 만들어 background에 rgb 값을 넣는다.
간략하게 하기 위해 es6에 Template Literals 이라고 해서 백틱(1 왼쪽과 탭 위에 있는 `) 안에 #{} 변수, 상수를 넣을수 있다.
Velopert 님의 동영상을 보며 공부하며 기억하기위해 정리한 글이니까 더 정확하고 좋은 설명은 아래 유튜브에서 참고하면 될듯.
https://youtu.be/bp_eliWWWRA
[React.js] 강좌 5-8편 Redux: react-redux | 컴포넌트에서 사용하기