mrbone / mrbone.github.io

0 stars 0 forks source link

Redux store 的 initialState #68

Closed mrbone closed 6 years ago

mrbone commented 6 years ago

Redux store 的 initialState

normal reducer

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';

const rootReducer = (state = {}, action)=> {
  return state;
}

const initialState = {
  static:{}
}

const store = createStore(
  rootReducer, 
  initialState,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)

const App = () => (
  <div>
    Hello world
  </div>
);

ReactDOM.render(
  <App/>,
  document.getElementById('app'),
)

这个时候我们的 store 的 state tree 一切正常

{
  'static': {}
}

with combine reducer

当我们使用 combineReducer 之后,

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { composeWithDevTools } from 'redux-devtools-extension';

const rootReducer = (state = {}, action)=> {
  return state;
}

const initialState = {
  static:{}
}

const store = createStore(
  combineReducers({
    dynamic:(state = {})=> state
  }), 
  initialState,
  composeWithDevTools()
)

const App = () => (
  <div>
    Hello world
  </div>
);

ReactDOM.render(
  <App/>,
  document.getElementById('app'),
)

控制台这个时候会给我们抛出一个错误

Unexpected key "static" found in previous state received by the reducer. Expected to find one of the known reducer keys instead: "dynamic". Unexpected keys will be ignored.

我们必须给 static 的 state 增加一个 reducer,如果是静态数据,我们也需要增加一个空的 reducer

const store = createStore(
  combineReducers({
    dynamic:(state = {})=> state,
+    static: (state = {}) => state
  }), 
  initialState,
  composeWithDevTools()
)

使用 Object.assign

为静态数据放一个空的 reducer 还是比较 tricky,社区中还有另外一个方案。

const store = createStore(
+  (state, action) => (Object.assign({}, initialState, state, combinedReducers(state, action))),
-  initialState,
  composeWithDevTools()
)

这种方式初次的 error message 就消失,但事实是这样么?我们再 dispatch 一个 action 会发现这个 error message 又出现了,因为 combinedReducers 会在非 production 下每次都检查 state 的 shape 是不是期望的格式,当发现有特殊 field 但是没有对应的 reducer 就会抛出这个错误。

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import mapValues from 'lodash/mapValues';

const rootReducer = (state = {}, action)=> {
  return state;
}

const initialState = {
  static:{
    setting:{}
  }
}

const combinedReducers = combineReducers({
  dynamic:(state = {}) => state
});

const reducers = {
  dynamic:(state = {}) => state
};

const store = createStore(
  combineReducers({
    ...mapValues(initialState, () => (state = {}) => state),
    ...reducers,
  }),
  initialState,
  composeWithDevTools()
)

const App = () => (
  <div>
    Hello world
  </div>
);

ReactDOM.render(
  <App/>,
  document.getElementById('app'),
)

最终通过给说有的 read-only state 都加了一个空的 reducer 解决了问题,还有一种解法是我们自己写一个 combine reducer 来解决此类问题。