Вот пример использования помощника set :
const REMOVE = () => REMOVE;
//helper to get state values
const get = (object, path, defaultValue) => {
const recur = (current, path, defaultValue) => {
if (current === undefined) {
return defaultValue;
}
if (path.length === 0) {
return current;
}
return recur(
current[path[0]],
path.slice(1),
defaultValue
);
};
return recur(object, path, defaultValue);
};
//helper to set state values
const set = (object, path, callback) => {
const setKey = (current, key, value) => {
if (Array.isArray(current)) {
return value === REMOVE
? current.filter((_, i) => key !== i)
: current.map((c, i) => (i === key ? value : c));
}
return value === REMOVE
? Object.entries(current).reduce((result, [k, v]) => {
if (k !== key) {
result[k] = v;
}
return result;
}, {})
: { ...current, [key]: value };
};
const recur = (current, path, newValue) => {
if (path.length === 1) {
return setKey(current, path[0], newValue);
}
return setKey(
current,
path[0],
recur(current[path[0]], path.slice(1), newValue)
);
};
const oldValue = get(object, path);
const newValue = callback(oldValue);
if (oldValue === newValue) {
return object;
}
return recur(object, path, newValue);
};
const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore } = Redux;
//action
const setNewBuild = (path, value) => ({
type: 'SET_NEW_BUILD',
path,
value,
});
const initialState = {
array: [
{
key: 'value',
obj: {
key1: 'value',
key2: 'value',
},
},
],
path: '',
value: '',
};
const reducer = (state = initialState, action) => {
const { type } = action;
if (type === 'SET_NEW_BUILD') {
const { path, value } = action;
return set(state, path, () => value);
}
return state;
};
const store = createStore(
reducer,
initialState,
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
);
const App = () => {
const state = useSelector((x) => x);
const dispatch = useDispatch();
return (
{JSON.stringify(state, undefined, 2)}
); }; ReactDOM.render ( , document.getElementById ('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<div id="root"></div>
Важные биты:
<button
onClick={() =>
dispatch(
// path is an array
setNewBuild(['array', 0, 'obj'], {
key1: 'change both key1',
key2: 'change both key2',
})
)
}
>
change array 0 obj
</button>
А в редукторе:
const { type } = action;
if (type === 'SET_NEW_BUILD') {
const { path, value } = action;
return set(state, path, () => value);
}