我正在清理我从一开始就错误的减速机设置。我使用redux doco和the ducks pattern来设置正确。
我希望将我的状态分开/分开,如doco suggests:
{
domainData1 : {},
domainData2 : {},
appState1 : {},
appState2 : {},
ui : {
uiState1 : {},
uiState2 : {},
}
}
在我的情况下,我有一些我想要管理的专辑,目录和照片。国家应该看起来像这样:
{
//domainData
albums : {...},
catalogs : {...},
photos : {...},
//appState
selectedAlbum : {...},
//uiState
ui : {
loading : {},
uiState2 : {},
}
}
我已将属于相册的所有代码放在一个文件中,其中包含操作,操作创建者,重复者和API 类似的目录和照片。 然后我将reducers和combineReducers组合在一个单独的文件中。
以下代码......
我的问题是......当我在相册上做东西时,我会希望所有的域数据都进入州的专辑分支。但是我不希望ui和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
});
对不起,很长的帖子 - 没有土豆
答案 0 :(得分:1)
您只需将该逻辑移动到负责该状态切片的Loading reducer。
// ducks/Loading.js
import {
REQUEST_ALBUM,
CREATE_ALBUM,
CREATE_ALBUM_SUCCESS
} from 'ducks/Albums'
// remember to also export from the Albums duck.
export const reducer = (state, action) => {
switch (action.type) {
case REQUEST_ALBUM:
case CREATE_ALBUM:
return state.set('loading', true)
case CREATE_ALBUM_SUCCESS:
return state.set('loading', false)
}
}
您可以从其他duck文件导入操作类型。
Albums
reducer只负责更新自己的状态切片。
多个Reducer可以侦听相同的动作类型,并对自己的切片进行一些更改。所以CREATE_ALBUM_SUCCESS
也可以触发Albums reducer中的一些更改。
您也可以通过其他方式实现此目的。例如,通过在操作的meta
字段中使用密钥。这避免了必须进行大量的导入和导出,因为reducer不必知道动作的类型。
// loading reducer
export const reducer = (state = false, action) =>
(action.meta && action.meta.loading !== undefined)
? action.meta.loading
: state
// action creator
export const updateAlbumPending = () => ({
type: UPDATE_ALBUM,
meta: {
loading: true
}
})