React 和Redux 都需要纯函数和不变性才能以可预测的方式运行。
如果您不遵循这两点,您的应用就会出现错误,最常见的是React/Redux 无法跟踪更改,并且当您的state/prop 更改时无法重新渲染。
就 React 而言,考虑以下示例:
let state = {
add: 0,
}
function render() {
//...
}
//pure function
function effects(state,action) {
//following immutability while updating state, not directly mutating the state.
if(action == 'addTen') {
return {...state, add: state.add + 10}
}
return state;
}
function shouldUpdate(s) {
if(s === state){
return false
}
return true
}
state = effects(state, 'addTen')if(shouldUpdate(state)) {
render();
}
状态由仅具有附加属性的状态对象持有。此应用呈现应用属性。它不应该总是在发生任何事情时呈现状态,而是应该检查状态对象中是否发生了变化。
像这样,我们有一个效果函数,一个pure function,我们用它来影响我们的状态。您会看到,当状态要更改时它会返回一个新状态,而当不需要修改时它会返回相同的状态。
我们还有一个 shouldUpdate 函数,它使用 === 运算符检查旧状态和新状态是否相同。
要在 React 方面犯错,您实际上可以执行以下操作:
function effects(state,action) {
doRandom(); // effects should only be called for updating state.
// Doing any other stuff here would make effects impure.
if(action == 'addTen') {
return {...state, add: state.add + 10}
}
return state;
}
你也可以通过直接设置状态而不使用effects函数来出错。
function doMistake(newValue) {
this.state = newValue
}
以上不应该做,只应该使用effects函数来更新状态。
在 React 方面,我们将 effects 称为 setState。
对于 Redux:
- Redux 的
combineReducers 实用程序检查引用更改。
- React-Redux 的
connect 方法生成组件,这些组件检查根状态和 mapState 函数的返回值的引用更改,以查看被包装的组件是否真的需要重新渲染。
- 时间穿梭调试要求reducer为
pure functions且无副作用,这样才能在不同状态之间正确跳转。
使用不纯函数作为reducer,很容易违反上述三点。
以下内容直接取自 redux 文档:
之所以称为reducer,是因为它是您将传递给Array.prototype.reduce(reducer, ?initialValue) 的函数类型。
减速器保持纯净是非常重要的。在 reducer 中你不应该做的事情:
Mutate its arguments;
Perform side effects like API calls and routing transitions;
Call non-pure functions, e.g. Date.now() or Math.random().
给定相同的参数,它应该计算下一个状态并返回它。没有惊喜。无副作用。没有 API 调用。没有突变。只是一个计算。