Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useSelector returns stale value in parent component if child class component dispatches action updating that value during life cycle functions #1601

Closed
tianenli opened this issue Jul 2, 2020 · 2 comments

Comments

@tianenli
Copy link

tianenli commented Jul 2, 2020

What is the current behavior?

This is related/displaying similar behavior to #1599.

In this example, our parent component consumes a value from the store, and a child component on componentDidMount and componentDidUpdate calls an action to update that value multiple times. We see the child component receives the updated value, while the parent component does not after the first update. The parent component's useSelector instance doesn't invoke the selector function and just returns the cached value.

https://codesandbox.io/s/race-condition-x1h1d

import React from "react";
import { incrementAction } from "./actions";
import { connect, useSelector } from "react-redux";

const countersSelector = state => {
  console.log("RUNNING SELECTOR", state.counters);
  return state.counters;
};

class ChildBase extends React.Component {
  componentDidMount() {
    if (this.props.counter < 3) {
      this.props.increment();
    }
  }

  componentDidUpdate() {
    if (this.props.counter < 3) {
      this.props.increment();
    }
  }

  render() {
    return <div>Child: {this.props.counter}</div>;
  }
}

const mapStateToProps = state => ({
  counter: state.counters.counter
});

const mapDispatchToProps = dispatch => ({
  increment: () => dispatch(incrementAction())
});

const Child = connect(
  mapStateToProps,
  mapDispatchToProps
)(ChildBase);

function App(props) {
  console.log("App CALLING USESELECTOR");
  const counters = useSelector(countersSelector);
  console.log(counters);

  return (
    <div className="App">
      <div>App: {counters.counter}</div>
      <Child />
    </div>
  );
}

export default App;

What is the expected behavior?

We would expect the parent component's useSelector instance to return the same value from the store as the child component's

Which versions of React, ReactDOM/React Native, Redux, and React Redux are you using? Which browser and OS are affected by this issue? Did this work in previous versions of React Redux?

The versions used in the code sandbox are:
react: 16.13.1
react-dom: 16.8.3
react-redux: 7.1.3
redux: 4.0.5

@timdorr
Copy link
Member

timdorr commented Jul 2, 2020

This is basically a duplicate of #1510, but between useSelector and connect If you delay the dispatches with a setTimeout, the problem also goes away.

@markerikson
Copy link
Contributor

I'm going to close this as a WONTFIX for now, largely because we're encouraging folks to stop using connect (even though it'll be fully supported in v8). This is a real bit of behavior that I can understand is annoying, but I don't think there's a meaningful change we can make at this point, and I don't intend to spend time fixing it myself.

If someone still feels strongly about this please comment, or even better file a PR to improve behavior here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants