[原文链接]https://blog.bam.tech/developper-news/4-ways-to-dispatch-actions-with-redux
redux 作为js app的主要的状态容器和react结合的非常多。架构设计上基于action的触发机制,通过dispatch对应的action来修改状态,而状态的修改由统一的reducer来处理(为什么叫reducer呢,因为每个都可以作为reduce函数的参数来处理)如果对redux的原理还不怎么熟悉,可以先读下这篇文章,当然是因为的,对应的中文是这篇。
我们在这里将重点放在了第一步,也就是如何dispatch分发一个action。接下来我们就来处理这个问题,同时尽量保证component组件与redux的解耦。
举例来说吧,我们假定这样一个服务场景:就是用户要发送一个message到一个群里。我们首先要创建个form表单(这里是MessageSending.js),另外还需要一个发送的按钮,当点击时将沃恩的消息发给对应的API后台。
PS:在下面的所有例子中,规定action creators 就叫actions
dispatch函数作为store对象的方法可以直接调用
// App.js
import { createStore } from 'redux';
import { MessageSending } from './MessageSending';
import reducer from './reducer';
const store = createStore(reducer);
class App extends React.Component {
render() {
<MessageSending store={store} />
};
};
// MessageSending.js
import { sendMessage } from './actions';
// ...
this.props.store.dispatch(sendMessage(message))
// ...
上面一种方法的缺点是component需要包含你的app逻辑,而redux的作者之一的Dan Abramov建议需要可以将逻辑connect到store里面(详情可以参见笔者翻译的另一篇文章,同样出自Dan Abramov,讲述Container组件与Presentation组件的区分)。所以我们就来实现下,创建一个MessageSending.container.js文件,在其中调用connect方法,而其中第二个参数function mapDispatchToProps,将所有的action creators做了封装,然后统一传递到组件中。
// MessageSending.container.js
import { connect } from 'react-redux';
import { sendMessage } from './actions';
import MessageSending from './MessageSending';
const mapDispatchToProps = {
sendMessage,
};
export default connect(null, mapDispatchToProps)(MessageSending);
// MessageSending.js
// ...
this.props.sendMessage(message);
// ...
If you want to dispatch several actions in one method you can do like that:
import { connect } from 'react-redux';
import { sendMessage, navigateTo } from './actions';
const mapDispatchToProps = dispatch => ({
sendMessage: messaga => {
dispatch(sendMessage(message));
dispatch(navigateTo({ routeName: 'messagesList' }));
},
});
export default connect(null, mapDispatchToProps)(MessageSending);
// MessageSending.js
// ...
this.props.sendMessage(message);
// ...
});
如果想要按顺序挨个执行多个异步的指令,同时还想保证状态可读,那么就可以通过触发一个saga来实现。在saga中可以在dispatch actions时带上put效果,想要了解更多的信息可以查阅redux-saga的文档。
// sagas.js
import { put } from 'redux-saga/effects';
import { sendMessage, setLoading, navigateTo } from './actions';
export function* sendMessage(action) {
yield put(setLoading('sendMessagePage', true));
yield put(sendMessage(action.payload.message));
yield put(navigateTo({routeName: 'messagesList'}));
yield put(setLoading('sendMessagePage', false));
}
bindActionCreators方法能让你在没有connect到store的组件上dispatch actions,就像借助mapDispatchToPros connect的一样。
这个方法的使用还是不高的,而且react-redux已经实现了相应的功能,所以说Redux的维护者Mark Erikson也建议不要使用它。
不过下面的例子是受了redux的启发,假定有个MessageSendingPage页面,页面已经connect完成,所以可以dispatch方法了。这个页面包含了一个MessageSending组件是完全不清楚redux存在的。
// MessageSendingPage.js
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as actions from './actions';
class MessageSendingPage extends React.Component {
constructor(props) {
super(props);
const { dispatch } = props;
this.boundActions = bindActionCreators(actions, dispatch);
}
render() {
return <MessageSending {...this.boundActions} />;
}
}
export default connect()(MessageSendingPage);
所以我们到底该如何选择呢?
很难说,完全取决于你的使用场景。不过就使用频率来看的话,第2和第3种是比较推荐的。