私はreduxとes6構文の初心者です。私は公式のreduxチュートリアルを使用してアプリを作成しますが、これは 例 です。
以下にJSスニペットがあります。私のポイント-投稿リデューサーでREQUEST_POST_BODYとRECEIVE_POST_BODYのケースを定義する。主な困難-ストア内の正しいオブジェクトを見つけて更新する。
私は例のコードを使用しようとします:
return Object.assign({}, state, {
[action.subreddit]: posts(state[action.subreddit], action)
})
しかし、投稿の単純な配列を使用しました。 IDで正しい投稿を見つける必要はありません。
ここに私のコード:
const initialState = {
items: [{id:3, title: '1984', isFetching:false}, {id:6, title: 'Mouse', isFetching:false}]
}
// Reducer for posts store
export default function posts(state = initialState, action) {
switch (action.type) {
case REQUEST_POST_BODY:
// here I need to set post.isFetching => true
case RECEIVE_POST_BODY:
// here I need to set post.isFetching => false and post.body => action.body
default:
return state;
}
}
function requestPostBody(id) {
return {
type: REQUEST_POST_BODY,
id
};
}
function receivePostBody(id, body_from_server) {
return {
type: RECEIVE_POST_BODY,
id,
body: body_from_server
};
}
dispatch(requestPostBody(3));
dispatch(receivePostBody(3, {id:3, body: 'blablabla'}));
配列に固執したい場合は、単一のpost
オブジェクトに取り組むリデューサーを作成できます。
export default function reducePost(post, action) {
if(post.id !== action.id) return post;
switch(action.type) {
case REQUEST_POST_BODY:
return Object.assign({}, post, { isFetching: true });
case RECEIVE_POST_BODY:
return Object.assign({}, post, { isFetching: false, body: action.body });
default:
return post;
}
ルートレデューサーは次のようになります。
export default function posts(state = initialState, action) {
return state.map(post => reducePost(post, action);
}
リスト内の各投稿に対して新しいレデューサーを実行するだけで、更新された投稿の配列を返します。この場合、一意のIDにより、必ず1つのアイテムのみが変更されます。
各アイテムに一意の文字列/番号IDがある場合、配列を反転して、代わりにobject
を使用できます。
const initialState = {
items: {
3: {id:3, title: '1984', isFetching:false},
6: {id:6, title: 'Mouse', isFetching:false}
};
}
その後、減速機を簡素化できます。
switch (action.type) {
case REQUEST_POST_BODY:
let id = action.id;
return Object.assign({}, state, {
[id]: Object.assign({}, state[id], { isFetching: true })
});
case RECEIVE_POST_BODY:
let id = action.id;
return Object.assign({}, state, {
[id]: Object.assign({}, state[id], {
isFetching: false,
body: action.body
})
});
default:
return state;
}
ES7構文を試して満足している場合は、Babelでオブジェクトスプレッド演算子を有効にし、Object.assign
の呼び出しを書き換えることができます。
switch (action.type) {
case REQUEST_POST_BODY:
let id = action.id;
return {
...state,
[id]: {...state[id], isFetching: true }
};
case RECEIVE_POST_BODY:
let id = action.id;
return {
...state,
[id]: {
...state[id],
isFetching: false,
body: action.body
}
};
default:
return state;
}
Spread構文の使用にあまり熱心でない場合は、Object.assign
をもう少し口当たりの良いものにすることも可能です。
function $set(...objects) {
return Object.assign({}, ...objects);
}
case RECEIVE_POST_BODY:
let id = action.id;
return $set(state, {
[id]: $set(state[id], {
isFetching: false,
body: action.body
})
});
私が正しく理解していれば、あなたが望む特定の投稿を得るのに問題があります。
まず、リデューサーを使用すると、配列とその中のオブジェクトも更新されるため、読み取りと保守が難しくなります。アレイを使用したレデューサーの構成について説明するこの ショートビデオ をご覧になることをお勧めします。そこで説明されている手法を使用して、コードを単純化できます。
あなたの場合、posts
減速機とpost
減速機を使用し、posts
減速機はpost
減速機を呼び出します。
作業に適したオブジェクトを見つけることに関して、ダンプリンスの提案はそれを容易にします。配列の代わりにオブジェクトマップを使用すると、簡単になります。ダンの答えからの関連するコードスニペット:
const initialState = {
items: {
3: {id:3, title: '1984', isFetching:false},
6: {id:6, title: 'Mouse', isFetching:false}
];
}
動作するObject.assign
を使用してオブジェクトレデューサーを実装しましたが、プロジェクトが成長し、多数の依存コンポーネントを追加すると、非常に効率が悪くなり、レンダリングが非常に遅くなります。
immer について知っていれば、最初からそれを使用していました。
基本的に、次のようにimmerを使用します。この例には、次のようなlayers
オブジェクトがあります。
const initialState = {
layers: {
'layer1': { selected: false },
'layer2': { selected: true }
}
}
Reducers.js(抽出)
import produce from 'immer'
import has from 'lodash/has'
export const layers = (state = null, action) => {
switch (action.type) {
case ADD_LAYER:
// Using `immer.produce` only for consistency
// clearly the whole object changes in this case.
return produce(state, layers => {
// Take a copy of the prebuilt layer
var layer = Object.assign({}, action.layer)
// Add some defaults
if (!has(layer, 'selected')) {
layer.selected = false
}
layers[action.id] = layer
})
case SELECT_LAYER:
return produce(state, layers => {
layers[action.id].selected = true
})
case UNSELECT_LAYER:
return produce(state, layers => {
layers[action.id].selected = false
})
default:
return state
}
}
Actions.js(抽出)
export const addLayer = id => ({
type: ADD_LAYER,
id
})
export const selectLayer = id => ({
type: SELECT_LAYER,
id
})
export const unSelectLayer = id => ({
type: UNSELECT_LAYER,
id
})
参照:
https://github.com/immerjs/immer
https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns