[reactjs] bindActionCreators는 언제 react / redux에서 사용됩니까?
bindActionCreators에 대한 Redux 문서는 다음과 같이 설명합니다.
에 대한 유일한 사용 사례
bindActionCreators
는 Redux를 인식하지 않는 구성 요소에 일부 작업 생성자를 전달하고 디스패치 또는 Redux 저장소를 전달하지 않으려는 경우입니다.
예를 들면 무엇입니까? bindActionCreators
사용 / 필요한 ?
Redux를 인식하지 못하는 구성 요소 유형 합니까?
두 옵션의 장점 / 단점은 무엇입니까?
//actionCreator
import * as actionCreators from './actionCreators'
function mapStateToProps(state) {
return {
posts: state.posts,
comments: state.comments
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actionCreators, dispatch)
}
vs
function mapStateToProps(state) {
return {
posts: state.posts,
comments: state.comments
}
}
function mapDispatchToProps(dispatch) {
return {
someCallback: (postId, index) => {
dispatch({
type: 'REMOVE_COMMENT',
postId,
index
})
}
}
}
답변
나는 가장 대중적인 대답이 실제로 질문을 다룬다 고 생각하지 않습니다.
아래의 모든 예제는 기본적으로 동일한 작업을 수행하고 “사전 바인딩”개념을 따르지 않습니다.
// option 1
const mapDispatchToProps = (dispatch) => ({
action: () => dispatch(action())
})
// option 2
const mapDispatchToProps = (dispatch) => ({
action: bindActionCreators(action, dispatch)
})
// option 3
const mapDispatchToProps = {
action: action
}
옵션 #3
은 옵션 의 속기 일 뿐이 #1
므로 옵션 #1
대 옵션을 사용하는 진짜 질문 #2
입니다. 나는 둘 다 react-redux 코드베이스에서 사용되는 것을 보았고 다소 혼란 스럽습니다.
나는 doc의 모든 예제 가 react-redux
사용 bindActionCreators
하는 반면 bindActionCreators 의 doc (질문 자체에서 인용)은 react-redux와 함께 사용하지 말라고 혼란스러워 합니다.
나는 대답은 코드베이스의 일관성 것 같아요,하지만 난 개인적으로 명시 적으로 조치 포장 선호 파견을 필요할 때마다.
답변
99 %의 connect()
경우 mapDispatchToProps
매개 변수의 일부로 React-Redux 기능 과 함께 사용됩니다 . mapDispatch
사용자가 제공 하는 함수 내에서 명시 적으로 사용할 수도 있고 , 객체 축약 구문을 사용하고 액션 생성자로 가득 찬 객체를에 전달하는 경우 자동으로 사용할 수도 있습니다 connect
.
아이디어는 액션 생성자를 미리 묶음으로써 전달되는 구성 요소가 connect()
기술적으로 연결되어 있다는 것을 “모르는”다는 것입니다. 단지 실행해야한다는 것만 알고 있습니다 this.props.someCallback()
. 반면에 액션 생성자를 바인드하지 않고를 호출 this.props.dispatch(someActionCreator())
하면 이제 컴포넌트는 props.dispatch
존재하기를 기대 하기 때문에 연결되었음을 “인식” 합니다.
내 블로그 게시물 Idiomatic Redux : Why use action creators? 에서이 주제에 대한 몇 가지 생각을 썼습니다 . .
답변
보다 완전한 예는 연결할 액션 생성자로 가득 찬 객체를 전달하는 것입니다.
import * as ProductActions from './ProductActions';
// component part
export function Product({ name, description }) {
return <div>
<button onClick={this.props.addProduct}>Add a product</button>
</div>
}
// container part
function mapStateToProps(state) {
return {...state};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
...ProductActions,
}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(Product);
답변
나는 원래의 질문에 대답하려고 노력할 것입니다 …
Smart & Dumb 구성 요소
첫 번째 질문에서 기본적으로 왜 bindActionCreators
필요한지, 그리고 어떤 종류의 구성 요소가 Redux를 인식하지 않아야하는지 묻습니다 .
요컨대 구성 요소는 스마트 (컨테이너) 및 멍청한 (프레젠테이션) 구성 요소 로 분리되어야한다는 것 입니다.
멍청한 구성 요소 는 알아야 할 필요에 따라 작동합니다. 그들의 영혼의 임무는 주어진 데이터를 HTML로만 렌더링하는 것입니다. 그들은 응용 프로그램의 내부 작동을 인식하지 않아야합니다. 응용 프로그램의 피부 깊숙한 전면 레이어로 볼 수 있습니다.
반면 스마트 구성 요소 는 일종의 접착제로, 멍청한 구성 요소에 대한 데이터를 준비 하고 HTML 렌더링을 수행하지 않는 것이 좋습니다.
이러한 종류의 아키텍처는 UI 계층과 그 아래에있는 데이터 계층 간의 느슨한 결합을 촉진합니다. 이것은 차례로 두 레이어 중 하나를 다른 레이어 (예 : 새로운 UI 디자인)로 쉽게 교체 할 수있게하여 다른 레이어를 손상시키지 않습니다.
귀하의 질문에 답하기 위해 : 멍청한 구성 요소는 Redux (또는 해당 문제에 대한 데이터 계층의 불필요한 구현 세부 사항)를 인식하지 않아야합니다. 왜냐하면 나중에 다른 것으로 교체하고 싶을 수 있기 때문입니다.
이 개념에 대한 자세한 내용은 Redux 매뉴얼 과 Dan Abramov의 Presentational and Container Components 기사에서 더 자세히 확인할 수 있습니다 .
어떤 예가 더 낫다
두 번째 질문은 주어진 예제의 장점 / 단점에 관한 것이 었습니다.
에서 첫 번째 예 작업 제작자는 별도의 정의 actionCreators
가 다른 재사용 될 수 있다는 것을 의미하는, 파일 / 모듈. 행동을 정의하는 표준적인 방법입니다. 나는 이것에 어떤 단점도 보이지 않는다.
두 번째 예 는 작업 작성자를 인라인으로 정의하며 여러 가지 단점이 있습니다.
- 액션 제작자는 재사용 할 수 없습니다 (분명히)
- 문제가 더 장황하여 읽기가 어렵습니다.
- 액션 유형은 하드 코딩
consts
되어 있습니다. 리듀서에서 참조 할 수 있도록 개별적 으로 정의하는 것이 좋습니다 . 그러면 입력 실수를 줄일 수 있습니다. - 액션 생성자를 인라인으로 정의하는 것은 권장 / 예상되는 사용 방법에 위배됩니다. 따라서 코드를 공유하려는 경우 커뮤니티에서 코드를 읽을 수 없게됩니다.
두 번째 예제는 첫 번째 예제 보다 한 가지 장점 이 있습니다. 작성하는 것이 더 빠릅니다! 따라서 코드에 대한 더 큰 계획이 없다면 괜찮을 수 있습니다.
나는 내가 일을 조금 명확히 할 수 있기를 바랍니다 …
답변
한 가지 가능한 용도는 bindActionCreators()
여러 액션을 하나의 소품으로 함께 “매핑”하는 것입니다.
일반적인 디스패치는 다음과 같습니다.
몇 가지 일반적인 사용자 작업을 소품에 매핑합니다.
const mapStateToProps = (state: IAppState) => {
return {
// map state here
}
}
const mapDispatchToProps = (dispatch: Dispatch) => {
return {
userLogin: () => {
dispatch(login());
},
userEditEmail: () => {
dispatch(editEmail());
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
대규모 프로젝트에서 각 디스패치를 개별적으로 매핑하는 것은 다루기 힘들 수 있습니다. 서로 관련된 많은 작업이있는 경우 이러한 작업을 결합 할 수 있습니다 . 예를 들어 모든 종류의 다른 사용자 관련 작업을 수행 한 사용자 작업 파일입니다. 각 액션을 별도의 디스패치로 호출하는 bindActionCreators()
대신 dispatch
.
bindActionCreators ()를 사용한 다중 디스패치
모든 관련 작업을 가져옵니다. redux 저장소의 동일한 파일에있을 가능성이 높습니다.
import * as allUserActions from "./store/actions/user";
이제 디스패치를 사용하는 대신 bindActionCreators ()를 사용하십시오.
const mapDispatchToProps = (dispatch: Dispatch) => {
return {
...bindActionCreators(allUserActions, dispatch);
},
};
};
export default connect(mapStateToProps, mapDispatchToProps,
(stateProps, dispatchProps, ownProps) => {
return {
...stateProps,
userAction: dispatchProps
ownProps,
}
})(MyComponent);
이제 소품 userAction
을 사용 하여 구성 요소의 모든 작업을 호출 할 수 있습니다 .
IE :
userAction.login()
userAction.editEmail()
또는
this.props.userAction.login()
this.props.userAction.editEmail()
.
참고 : bindActionCreators ()를 단일 소품에 매핑 할 필요는 없습니다. ( => {return {}}
에 매핑 되는 추가 userAction
). 를 사용 bindActionCreators()
하여 단일 파일의 모든 작업을 별도의 소품으로 매핑 할 수도 있습니다 . 하지만 그렇게하는 것이 혼란 스러울 수 있습니다. 각 작업 또는 “작업 그룹”에 명시적인 이름을 지정하는 것을 선호합니다. 또한 ownProps
이 “하위 소품”이 무엇인지 또는 어디에서 왔는지에 대해 더 설명하기 위해의 이름을 지정하고 싶습니다 . Redux + React를 사용할 때 모든 소품이 제공되는 위치가 약간 혼란스러워서 설명이 많을수록 좋습니다.
답변
를 사용하여 bindActionCreators
여러 액션 함수를 그룹화 하여 Redux (Dumb Component)를 인식하지 못하는 컴포넌트에 다음과 같이 전달할 수 있습니다.
// actions.js
export const increment = () => ({
type: 'INCREMENT'
})
export const decrement = () => ({
type: 'DECREMENT'
})
// main.js
import { Component } from 'react'
import { bindActionCreators } from 'redux'
import * as Actions from './actions.js'
import Counter from './counter.js'
class Main extends Component {
constructor(props) {
super(props);
const { dispatch } = props;
this.boundActionCreators = bindActionCreators(Actions, dispatch)
}
render() {
return (
<Counter {...this.boundActionCreators} />
)
}
}
// counter.js
import { Component } from 'react'
export default Counter extends Component {
render() {
<div>
<button onclick={() => this.props.increment()}
<button onclick={() => this.props.decrement()}
</div>
}
}
답변
또한 bindActionsCreators 에 대해 더 많이 알고 싶었고 여기에 내 프로젝트에서 구현 한 방법이 있습니다.
// Actions.js
// Action Creator
const loginRequest = (username, password) => {
return {
type: 'LOGIN_REQUEST',
username,
password,
}
}
const logoutRequest = () => {
return {
type: 'LOGOUT_REQUEST'
}
}
export default { loginRequest, logoutRequest };
React 컴포넌트에서
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import ActionCreators from './actions'
class App extends Component {
componentDidMount() {
// now you can access your action creators from props.
this.props.loginRequest('username', 'password');
}
render() {
return null;
}
}
const mapStateToProps = () => null;
const mapDispatchToProps = dispatch => ({ ...bindActionCreators(ActionCreators, dispatch) });
export default connect(
mapStateToProps,
mapDispatchToProps,
)(App);