В проекте React-Redux люди обычно создают несколько действий и редукторов для каждого подключенного компонента. Однако это создает много кода для простых обновлений данных.
Хорошей практикой является использование единого родового действия и редуктора для инкапсуляции всех изменений данных, чтобы упростить и закрепить разработку приложений.
Каковы были бы недостатки или потеря производительности при использовании этого метода. Потому что я не вижу существенного компромисса, и это делает разработку намного проще, и мы можем поместить все их в один файл! Пример такой архитектуры:
// Say we're in user.js, User page
// state
var initialState = {};
// generic action --> we only need to write ONE DISPATCHER
function setState(obj){
Store.dispatch({ type: 'SET_USER', data: obj });
}
// generic reducer --> we only need to write ONE ACTION REDUCER
function userReducer = function(state = initialState, action){
switch (action.type) {
case 'SET_USER': return { ...state, ...action.data };
default: return state;
}
};
// define component
var User = React.createClass({
render: function(){
// Here the magic...
// We can just call the generic setState() to update any data.
// No need to create separate dispatchers and reducers,
// thus greatly simplifying and fasten app development.
return [
<div onClick={() => setState({ someField: 1 })}/>,
<div onClick={() => setState({ someOtherField: 2, randomField: 3 })}/>,
<div onClick={() => setState({ orJustAnything: [1,2,3] })}/>
]
}
});
// register component for data update
function mapStateToProps(state){
return { ...state.user };
}
export default connect(mapStateToProps)(User);
редактировать
Таким образом, типичная архитектура Redux предлагает создать:
- Централизованные файлы со всеми действиями
- Централизованные файлы со всеми редукторами
Вопрос в том, почему двухэтапный процесс? Здесь другое архитектурное предложение:
Создайте 1 набор файлов, содержащих все setXField()
которые обрабатывают все изменения данных. И другие компоненты просто используют их для запуска изменений. Легко. Пример:
/** UserAPI.js
* Containing all methods for User.
* Other components can just call them.
*/
// state
var initialState = {};
// generic action
function setState(obj){
Store.dispatch({ type: 'SET_USER', data: obj });
}
// generic reducer
function userReducer = function(state = initialState, action){
switch (action.type) {
case 'SET_USER': return { ...state, ...action.data };
default: return state;
}
};
// API that we export
let UserAPI = {};
// set user name
UserAPI.setName = function(name){
$.post('/user/name', { name }, function({ ajaxSuccess }){
if (ajaxSuccess) setState({ name });
});
};
// set user picture URL
UserAPI.setPicture = function(url){
$.post('/user/picture', { url }, function({ ajaxSuccess }){
if (ajaxSuccess) setState({ url });
});
};
// logout, clear user
UserAPI.logout = function(){
$.post('/logout', {}, function(){
setState(initialState);
});
};
// Etc, you got the idea...
// Moreover, you can add a bunch of other User related methods,
// like some helper methods unrelated to Redux, or Ajax getters.
// Now you have everything related to User available in a single file!
// It becomes much easier to read through and understand.
// Finally, you can export a single UserAPI object, so other
// components only need to import it once.
export default UserAPI
Прочитайте комментарии в разделе выше.
Теперь вместо того, чтобы иметь кучу действий/диспетчеров/редукторов. У вас есть 1 файл, инкапсулирующий все необходимое для концепции пользователя. Почему это плохая практика? IMO, это значительно облегчает жизнь программиста, и другие программисты могут просто читать файл сверху донизу, чтобы понять бизнес-логику, им не нужно переключаться между файлами действий/редукторов. Черт возьми, даже redux-thunk
не нужна! И вы можете даже проверять функции один за другим. Поэтому тестируемость не теряется.