[原文鏈接]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
方法1: 直接通過dispatch方法
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))
// ...
方法2:使用react-redux
上面一種方法的缺點是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);
// ...
});
方法3: 通過saga來dispatch action
如果想要按順序挨個執行多個異步的指令,同時還想保證狀態可讀,那麼就可以通過觸發一個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));
}
方法4:使用bindActionCreators方法
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種是比較推薦的。