重新选择选择器使用相同的输入不断重新计算
Reselect selector keeps recomputing with the same input
我不明白为什么重新选择库会使用相同的输入重新计算选择器。我检查了 FAQ,但它没有回答我的问题。
这里有一个 react、redux、reselect 的例子
import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider, connect } from "react-redux";
import { createSelector } from "reselect";
const initialState = {
counter: 1
};
const reducer = (state = initialState, action) => {
if (action.type === "INCREMENT") {
return { ...state, counter: state.counter + 1 };
}
if (action.type === "DECREMENT") {
return { ...state, counter: state.counter - 1 };
}
return state;
};
const store = createStore(reducer);
class ChildComp extends React.Component {
handleIncrement = () => {
this.props.increment();
};
handleDecrement = () => {
this.props.decrement();
};
render() {
const { counter, isEven } = this.props;
return (
<div>
<div>counter: {counter}</div>
<div>is even: {JSON.stringify(isEven)}</div>
<button onClick={this.handleIncrement}>increment</button>
<button onClick={this.handleDecrement}>decrement</button>
</div>
);
}
}
const getCounter = state => state.counter;
const isEvenSelector = createSelector(
getCounter,
counter => {
console.log("calculate is even for", counter);
return counter % 2 === 0;
}
);
const mapStateToProps = state => {
return {
counter: state.counter,
isEven: isEvenSelector(state)
};
};
const mapDispatchToProps = dispatch => {
return {
increment: () => dispatch({ type: "INCREMENT" }),
decrement: () => dispatch({ type: "DECREMENT" })
};
};
const Child = connect(
mapStateToProps,
mapDispatchToProps
)(ChildComp);
class App extends React.Component {
render() {
return (
<Provider store={store}>
<Child />
</Provider>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
预期行为:
initial (counter 1) // 计算为偶数 1
increment (counter 2) // 计算对于 2
是偶数
decrement (counter 1) // 不应该console.log,因为结果已经计算
实际行为:
initial (counter 1) // 计算为偶数 1
increment (counter 2) // 计算对于 2
是偶数
decrement (counter 1) // 计算对于 1
是偶数
仅缓存前一组输入的结果。
Selectors created with createSelector have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector.
所以,如果计数器的值没有改变,那么您将看不到控制台日志。但是因为和上次选择器函数执行的结果不一样,所以需要重新计算。
我不明白为什么重新选择库会使用相同的输入重新计算选择器。我检查了 FAQ,但它没有回答我的问题。
这里有一个 react、redux、reselect 的例子
import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider, connect } from "react-redux";
import { createSelector } from "reselect";
const initialState = {
counter: 1
};
const reducer = (state = initialState, action) => {
if (action.type === "INCREMENT") {
return { ...state, counter: state.counter + 1 };
}
if (action.type === "DECREMENT") {
return { ...state, counter: state.counter - 1 };
}
return state;
};
const store = createStore(reducer);
class ChildComp extends React.Component {
handleIncrement = () => {
this.props.increment();
};
handleDecrement = () => {
this.props.decrement();
};
render() {
const { counter, isEven } = this.props;
return (
<div>
<div>counter: {counter}</div>
<div>is even: {JSON.stringify(isEven)}</div>
<button onClick={this.handleIncrement}>increment</button>
<button onClick={this.handleDecrement}>decrement</button>
</div>
);
}
}
const getCounter = state => state.counter;
const isEvenSelector = createSelector(
getCounter,
counter => {
console.log("calculate is even for", counter);
return counter % 2 === 0;
}
);
const mapStateToProps = state => {
return {
counter: state.counter,
isEven: isEvenSelector(state)
};
};
const mapDispatchToProps = dispatch => {
return {
increment: () => dispatch({ type: "INCREMENT" }),
decrement: () => dispatch({ type: "DECREMENT" })
};
};
const Child = connect(
mapStateToProps,
mapDispatchToProps
)(ChildComp);
class App extends React.Component {
render() {
return (
<Provider store={store}>
<Child />
</Provider>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
预期行为:
initial (counter 1) // 计算为偶数 1
increment (counter 2) // 计算对于 2
是偶数
decrement (counter 1) // 不应该console.log,因为结果已经计算
实际行为:
initial (counter 1) // 计算为偶数 1
increment (counter 2) // 计算对于 2
是偶数
decrement (counter 1) // 计算对于 1
仅缓存前一组输入的结果。
Selectors created with createSelector have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector.
所以,如果计数器的值没有改变,那么您将看不到控制台日志。但是因为和上次选择器函数执行的结果不一样,所以需要重新计算。