Reputation: 1971
I don't understand why reselect library re-calculates selector with the same input. I checked FAQ, but it doesn't answer my question.
Here's an example with 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);
Expected behavior:
initial (counter 1) // calculate is even for 1
increment (counter 2) // calculate is even for 2
decrement (counter 1) // shouldn't console.log, because the result was already calculated
Actual behavior:
initial (counter 1) // calculate is even for 1
increment (counter 2) // calculate is even for 2
decrement (counter 1) // calculate is even for 1
Upvotes: 1
Views: 588
Reputation: 1927
Only the result for the previous set of inputs is cached.
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.
So, if the value for counter hadn't changed then you would see no console log. But as it isn't the same as the last time the selector function executed the result has to be calculated again.
Upvotes: 3