【发布时间】:2017-07-08 12:51:18
【问题描述】:
我正在清理我的减速器设置,这从一开始就是错误的。我使用redux doco 和the ducks pattern 来设置它。
我想像doco suggests 一样分离/划分我的状态:
{
domainData1 : {},
domainData2 : {},
appState1 : {},
appState2 : {},
ui : {
uiState1 : {},
uiState2 : {},
}
}
就我而言,我有一些我正在尝试管理的相册、目录和照片。状态应该如下所示:
{
//domainData
albums : {...},
catalogs : {...},
photos : {...},
//appState
selectedAlbum : {...},
//uiState
ui : {
loading : {},
uiState2 : {},
}
}
我已将属于相册的所有代码放在动作、动作创建者、recuder 和 API 所在的一个文件中 类似的目录和照片。 然后我将 reducer 与 combineReducers 合并到一个单独的文件中。
代码如下...
我的问题是……当我在专辑上做事时,我希望所有域数据都进入该州的专辑分支。但我不希望 ui 和 app 状态的东西进入相册分支 - 这应该进入 app 和 ui 状态分支。这在我的设置中是不可能的,例如加载专辑时,我在“专辑”减速器中设置了加载标志,这是直到 combineReducer 的馈送,结果是加载状态成为状态的专辑分支的一部分......
相册模块:
import { createRequest, responseHandler, notAuthorized } from './apiUtils';
import { List, Map, fromJS } from 'immutable';
//actions
const REQUEST_ALBUMS = 'REQUEST_ALBUMS';
const FETCH_ALBUMS_SUCCESS = 'FETCH_ALBUMS_SUCCESS';
const FETCH_ALBUM_SUCCESS = 'FETCH_ALBUM_SUCCESS';
const REQUEST_ALBUM = 'REQUEST_ALBUM';
const CREATE_ALBUM = 'CREATE_ALBUM';
const CREATE_ALBUM_SUCCESS = 'CREATE_ALBUM_SUCCESS';
const UPDATE_ALBUM = 'UPDATE_ALBUM';
const UPDATE_ALBUM_SUCCESS = 'UPDATE_ALBUM_SUCCESS';
// Reducer
var init = Map(fromJS({
albums: [],
album: [],
loading: false,
}));
var newState = null;
export function reducer(state=init, action={}) {
switch (action.type) {
case FETCH_ALBUMS_SUCCESS: {
newState = state
.set('albums', fromJS(action.payload.albums))
.set('loading', false);
return newState;
}
case REQUEST_ALBUMS: {
return state.set('loading', true);
}
case FETCH_ALBUM_SUCCESS: {
newState = state
.set('album', fromJS(action.payload.album))
.set('loading', false);
return newState;
}
case REQUEST_ALBUM: {
return state.set('loading', true);
}
case CREATE_ALBUM: {
return state.set('loading', true);
}
case CREATE_ALBUM_SUCCESS: {
newState = state
.set('album', fromJS(action.payload.album))
.set('loading', false);
return newState;
}
case UPDATE_ALBUM: {
return state.set('loading', true);
}
case UPDATE_ALBUM_SUCCESS: {
newState = state
.set('album', fromJS(action.payload.album))
.set('loading', false);
return newState;
}
}
return state;
}
// Action Creators
export function getAlbumsPending(response) {
return {
type: REQUEST_ALBUMS,
};
}
export function getAlbumsSuccess(response) {
return {
type: FETCH_ALBUMS_SUCCESS,
payload: response,
};
}
export function getAlbumPending(response) {
return {
type: REQUEST_ALBUM,
};
}
export function getAlbumSuccess(response) {
return {
type: FETCH_ALBUM_SUCCESS,
payload: response,
};
}
function createAlbumPending(response) {
return {
type: CREATE_ALBUM,
};
}
function createAlbumSuccess(response) {
return {
type: CREATE_ALBUM_SUCCESS,
payload: response,
};
}
export function updateAlbumPending(response) {
return {
type: UPDATE_ALBUM,
};
}
export function updateAlbumSuccess(response) {
return {
type: UPDATE_ALBUM_SUCCESS,
payload: response,
};
}
//API
export function fetchAlbums() {
//API url
const url = '/api/albums.json';
//make the call
return dispatch => {
dispatch(getAlbumsPending());
fetch(createRequest('GET', url, null))
.then(response => responseHandler(response))
.then(data => dispatch(getAlbumsSuccess(data)))
.catch(error => console.log('request failed', error));
};
}
export function fetchAlbum(id) {
//url
var url = '/api/albums/'.concat(id);
return dispatch => {
dispatch(getAlbumPending());
fetch(createRequest('GET', url, null))
.then(response => responseHandler(response))
.then(data => dispatch(getAlbumSuccess({ album: data })))
.catch(error => console.log('request failed', error));
};
}
export function createAlbum(params) {
//API url
const url = '/api/albums/';
return dispatch => {
dispatch(createAlbumPending());
fetch(createRequest('POST', url, params))
.then(response => responseHandler(response))
.then(data => dispatch(createAlbumSuccess({ album: data })))
.catch(error => console.log('request failed', error));
};
}
export function updateAlbum(params) {
//API url
var url = '/api/albums/'.concat(params.id);
//make the call
return dispatch => {
dispatch(updateAlbumPending());
fetch(createRequest('PUT', url, params))
.then(response => responseHandler(response))
.then(data => dispatch(updateAlbumSuccess({ album: data })))
.catch(error => console.log('request failed', error));
};
}
CombineRecucer:
import { combineReducers } from 'redux';
import { reducer as albumReducer } from '../actions/album';
import { reducer as catalogReducer } from '../actions/catalog';
export default combineReducers({
albums: albumReducer, // <- loading flag ends up here
catalogs: catalogReducer,
loading: // I want loading flag here
});
抱歉发了这么长的帖子-没有土豆
【问题讨论】:
-
您必须在
loading减速器中添加case UPDATE_ALBUM:内容。您可以从其他鸭子文件中导入动作类型。相册 reducer 只负责更新它自己的状态切片。多个 reducer 可以监听相同的 action 类型,并对自己的 slice 进行一些更改。 -
OMG...如此简单.. 我完全错过了 redux 的天才...@HåkenLid 提出了一个答案,所以我可以相信你
-
当然。我已经添加了答案。
-
与你的实际问题完全无关:我不知道你认为你在用
newState变量做什么,但你不是。一般来说,当你编写函数式代码(包括 Redux 代码)时,尽量使用const而不是var——很多事情会变得更清晰。 -
感谢@Malvolio 的好建议
标签: reactjs redux react-redux