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

Expected state to match memoized state before componentDidMount #18090

Closed
padlock98 opened this issue Feb 20, 2020 · 9 comments
Closed

Expected state to match memoized state before componentDidMount #18090

padlock98 opened this issue Feb 20, 2020 · 9 comments
Labels
Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug

Comments

@padlock98
Copy link

Upgrading meteor (from 1.4 to 1.7) and react (from 15.3.2 to 16.8.6) and got this warning at browser console:

Warning: Expected Container(Container(withRouter(List))) state to match memoized state before componentDidMount. This might either be because of a bug in React, or because a component reassigns its own `this.props`. Please file an issue.
    in Container(Container(withRouter(List))) (created by UseDeps(Container(Container(withRouter(List)))))
    in UseDeps(Container(Container(withRouter(List)))) (created by RouterContext)
    in div (created by Layout)
    in div (created by Content)
    in Content (created by Layout)
    in div (created by Layout)
    in div (created by Layout)
    in MDLComponent (created by Layout)
    in Layout (created by Layout)
    in Layout (created by WithDeps(Layout))
    in WithDeps(Layout) (created by RouterContext)
    in RouterContext (created by Router)
    in Router
    in Provider
    in Unknown

Note: My codes ain't using react-css-modules or having this.props = ... syntax as suggested in #14224

React version: 16.8.6

Steps To Reproduce

Here is my code (which I have narrowed down to, likely at onPropsChange part)

list.js

import {useDeps, composeAll, compose} from 'mantra-core-extra';
import composeWithTracker from '../../core/libs/utils/compose-with-tracker';

import List from '../components/list.jsx';

import Tickets from '../../../../lib/collections';

const composer = ({context}, onData) => {
  const {Meteor, Store} = context();
  if (Meteor.subscribe('tickets').ready()) {
    let filters = Object.assign({}, Store.getState().tickets.list.filters);
    if (filters.date) {
      filters['createdAt'] = {$gt: filters.date.range.start, $lt: filters.date.range.end};
      delete filters['date'];
    }

    let total = Tickets.find(filters).count();
    const tickets = Tickets.find(filters, {
      sort: {[Store.getState().tickets.list.sort.field]: Store.getState().tickets.list.sort.order ? 1 : -1},
      skip: Store.getState().tickets.list.page * Store.getState().tickets.list.range,
      limit: Store.getState().tickets.list.range,
    }).fetch();
    onData(null, {tickets, total});
  }
};

const onPropsChange = ({context}, onData) => {
  const {Store} = context();
  onData(null, Store.getState().tickets);
  return Store.subscribe(() => {
    onData(null, Store.getState().tickets);
  });
};

const depsMapper = (context, actions) => ({
  select: actions.ticket.select,
  unselect: actions.ticket.unselect,
  remove: actions.ticket.remove,
  changePage: actions.ticket.changePage,
  sortField: actions.ticket.sort,
  changeCategory: actions.ticket.changeCategory,
  changeStatus: actions.ticket.changeStatus,
  changeDate: actions.ticket.changeDate,
  find: actions.ticket.find,
  context: () => context
});

export default composeAll(
  composeWithTracker(composer),
  compose(onPropsChange),
  useDeps(depsMapper)
)(List);

The current behavior

Causing table listing not appearing in my case.

The expected behavior

Table with rows of data to be listed

@padlock98 padlock98 added the Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug label Feb 20, 2020
@padlock98 padlock98 changed the title Bug: Expected state to match memoized state before componentDidMount Feb 20, 2020
@jddxf
Copy link
Contributor

jddxf commented Feb 21, 2020

The warning is a little misleading. What actually happens here is something is reassigning this.state not this.props. The only case I can now think of is as this example shows.

sophiebits added a commit to sophiebits/react that referenced this issue Feb 22, 2020
sophiebits added a commit to sophiebits/react that referenced this issue Feb 22, 2020
@sophiebits
Copy link
Collaborator

@jddxf is right; this warning should reference this.state#18103 will address that.

As for why you're encountering this in your own app, it's almost certainly because you are reassigning this.state (or one of your dependencies is). Unfortunately we can't help much without a repro case – if you try to look at your app and can't find where that assignment could be, then post a way to repro this and we can investigate.

(If you find that you're hitting this where no one is setting this.state, that would likely be a bug in React and we can reopen in that case.)

@padlock98
Copy link
Author

@jddxf @sophiebits thank you for your replies.

A question, is this just a warning or it will actually be show-stopper? Is it OK if I could ignore it and my codes still run?

@sophiebits
Copy link
Collaborator

I can't point to any concrete problems it will cause today, but I would recommend against it. There may be incompatibilities with future versions of React.

threepointone pushed a commit that referenced this issue Feb 28, 2020
@padlock98
Copy link
Author

Have narrowed down the problem to:

const onPropsChange = ({context}, onData) => {
  const {Store} = context();
  onData(null, Store.getState().payment);
  return Store.subscribe(() => {
    onData(null, Store.getState().payment);
  });
};

... particularly the return Store.subscribe part.

Perhaps, any expert here can suggest alternative code to overcome this please? @sophiebits ?

@sophiebits
Copy link
Collaborator

There's nothing wrong with the code you quoted in isolation, though it would depend what Store.subscribe and onData do.

@padlock98
Copy link
Author

Hmm, then really clueless to me. As the isolated part is redux thing. Shouldn't trigger said warning. Thank you anyway.

@rsshilli
Copy link

rsshilli commented Apr 9, 2020

For the next pour soul, I had the following code:

      this.state = {...this.state, ...newState};

And I fixed this error by doing this instead:

      for(const key of Object.keys(newState)) {
        this.state[key] = newState[key];
      }

This code was all running before the React component had a chance to mount, of course.

@gaearon
Copy link
Collaborator

gaearon commented Apr 10, 2020

Why not prepare the object first and then this.state = yourObj? Assuming as you said this happens in constructor?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug
Projects
None yet
Development

No branches or pull requests

5 participants