1.使用
在redux开发中我们经常会在写reducer的时候进行浅拷贝, 脚本如下
export default function mainInfo (state = initialState, action) {
let newState = Object.assign({}, state);
...
}
目的也只是为了"骗"redux进行刷新,作者也会考虑的该库的效率,不会进行深层的对比.
2.原理
对于以上问题,我们也可以查看下为什么一定要进行浅拷贝.
2.1 redux源码
进入redux源码中combineReducers.js文件的最后,我们可以看到
...
const nextState = {}
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
const reducer = finalReducers[key]
const previousStateForKey = state[key]
const nextStateForKey = reducer(previousStateForKey, action)
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
其中finalReducerKeys就是我们经常使用的方法合成reducer的combineReducers中参数, 如:
import { combineReducers } from 'redux';
import userinfo from './userinfo';
import main from './main.js';
export default combineReducers({
userinfo, main
});
不知道你注意了没有, hasChanged决定了最后返回的是nextState还是state,前者是新的对象,后者是原来的对象.
2.2 react-redux源码
进入Provider.js文件中,我们可以看到subscribe方法如下:
subscribe() {
const { store } = this.props
this.unsubscribe = store.subscribe(() => {
const newStoreState = store.getState()
if (!this._isMounted) {
return
}
this.setState(providerState => {
// If the value is the same, skip the unnecessary state update.
if (providerState.storeState === newStoreState) {
return null
}
return { storeState: newStoreState }
})
})
// Actions might have been dispatched between render and mount - handle those
const postMountStoreState = store.getState()
if (postMountStoreState !== this.state.storeState) {
this.setState({ storeState: postMountStoreState })
}
}
看他的订阅方法,其中newStoreState就是我们在2.1中看到返回的state.最后他会通过setState来进行重新渲染.它这里就是使用了之前记录的的storeState和现在获取到的newStoreState进行全等判断. 看到了吧,如果2.1中返回新state和旧state的区别了吧.
3.结论
如果想"骗"reducer刷新,就得在reducer中浅拷贝.
4.其他
如果使用了reducer的浅拷贝还是没有刷新页面,那么可能有如下原因.
1.在react层面,组件使用了PureComponent,connect包裹后.mapStateToProps返回的对象,每一个key对应的值没有被浅拷贝(或者是指针没有改变,导致全等判断结果)
2.是否在shouldComponentUpdate中写了相关逻辑
3.其他地方是否报错