By Joe Lewis


2016-11-02 17:27:48 8 Comments

I'm probably missing something very obvious and would like to clear myself.

Here's my understanding.
In a naive react component, we have states & props. Updating state with setState re-renders the entire component. props are mostly read only and updating them doesn't make sense.

In a react component that subscribes to a redux store, via something like store.subscribe(render), it obviously re-renders for every time store is updated.

react-redux has a helper connect() that injects part of the state tree (that is of interest to the component) and actionCreators as props to the component, usually via something like

const TodoListComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

But with the understanding that a setState is essential for the TodoListComponent to react to redux state tree change(re-render), I can't find any state or setState related code in the TodoList component file. It reads something like this:

const TodoList = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

Can someone point me in the right direction as to what I am missing?

P.S I'm following the todo list example bundled with the redux package(https://github.com/reactjs/redux/tree/master/examples/todos/src/containers).

3 comments

@markerikson 2016-11-02 17:31:23

The connect function generates a wrapper component that subscribes to the store. When an action is dispatched, the wrapper component's callback is notified. It then runs your mapState function, and shallow-compares the result object from this time vs the result object from last time (so if you were to rewrite a redux store field with its same value, it would not trigger a re-render). If the results are different, then it passes the results to your "real" component" as props.

Dan Abramov wrote a great simplified version of connect at https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e that illustrates the basic idea, although it doesn't show any of the optimization work. I also have links to a number of articles on Redux performance that discuss some related ideas.

@Joe Lewis 2016-11-02 18:17:38

Thanks! Are you the same person who helped me the other day @ HN - news.ycombinator.com/item?id=12307621 with useful links? Nice to meet you :)

@markerikson 2016-11-02 18:31:28

Yup, that's me :) I spend way too much time looking for discussions on Redux online - Reddit, HN, SO, Medium, and various other places. Glad to help! (Also FYI, I highly recommend the Reactiflux chat channels on Discord. Lots of people hanging out there and answering questions. I'm usually online there evenings US EST. Invite link is at reactiflux.com .)

@markerikson 2016-11-03 16:26:46

Assuming this answered the question, mind accepting the answer? :)

@Andy 2017-07-09 23:21:03

Is it comparing the objects themselves or the properties of those before/after objects? If it's the latter, does it only check the first level, is that what you mean by "shallow?"

@markerikson 2017-07-10 00:20:00

Yes, a "shallow equality check" means to compare the first level fields of each object: prev.a === current.a && prev.b === current.b && ...... That assumes that any data changes will result in new references, which means immutable data updates are required instead of direct mutation.

@asparism 2018-02-28 10:02:40

That Dan Abramov gist was a good resource

@ghazaleh javaheri 2018-12-05 12:34:20

as i know only thing redux does ,on change of store's state is calling componentWillRecieveProps if your component was dependent to mutated state and then you should force your component to update its is like this

1-store State change-2-call(componentWillRecieveProps(()=>{3-component state change}))

@SherylHohman 2018-02-03 02:51:53

My answer is a little out of left field. It sheds light on a problem that led me to this post. In my case it seemed the app was Not re-rendering, even though it received new props.
React devs had an answer to this often asked question something to the tune that if the (store) was mutated, 99% of the time that's the reason react won't re-render. Yet nothing about the other 1%. Mutation was not the case here.


TLDR;

componentWillReceiveProps is how the state can be kept synced with the new props.

Edge Case: Once state updates, then the app does re-render !


It turn out that if your app is using only state to display its elements, props can update, but state won't, so no re-render.

I had state that was dependent on props received from redux store. The data I needed wasn't in the store yet, so I fetched it from componentDidMount, as is proper. I got the props back, when my reducer updated store, because my component is connected via mapStateToProps. But the page didn't render, and state was still full of empty strings.

An example of this is say a user loaded an "edit post" page from a saved url. You have access to the postId from the url, but the info isn't in store yet, so you fetch it. The items on your page are controlled components - so all the data you're displaying is in state.

Using redux, the data was fetched, store was updated, and the component is connected, but the app didn't reflect the changes. On closer look, props were received, but app didn't update. state didn't update.

Well, props will update and propagate, but state won't. You need to specifically tell state to update.

You can't do this in render(), and componentDidMount already finished it's cycles.

componentWillReceiveProps is where you update state properties that depend on a changed prop value.

Example Usage:

componentWillReceiveProps(nextProps){
  if (this.props.post.category !== nextProps.post.category){
    this.setState({
      title: nextProps.post.title,
      body: nextProps.post.body,
      category: nextProps.post.category,
    })
  }      
}

I must give a shout out to this article that enlightened me on the solution that dozens of other posts, blogs, and repos failed to mention. Anyone else who has had trouble finding an answer to this evidently obscure problem, Here it is:

ReactJs component lifecycle methods — A deep dive

componentWillReceiveProps is where you'll update state to keep in sync with props updates.

Once state updates, then fields depending on state do re-render !

@kyw 2018-07-16 10:16:09

From React 16.3 onwards, you should use the getDerivedStateFromProps instead of componentWillReceiveProps. But in fact, you shouldn't even do all that as articulated here

Related Questions

Sponsored Content

22 Answered Questions

[SOLVED] What is the difference between state and props in React?

  • 2015-01-16 19:28:27
  • skaterdav85
  • 114579 View
  • 334 Score
  • 22 Answer
  • Tags:   javascript reactjs

8 Answered Questions

[SOLVED] Why use Redux over Facebook Flux?

5 Answered Questions

[SOLVED] How to pass actions down to the components in redux

1 Answered Questions

[SOLVED] Redux thunk , Connect ,ApplyMiddlerware ,

  • 2018-05-04 05:30:42
  • user4485357
  • 49 View
  • 0 Score
  • 1 Answer
  • Tags:   redux react-redux

1 Answered Questions

1 Answered Questions

[SOLVED] List not rendering to parent component

  • 2018-03-27 08:14:54
  • devd_102
  • 27 View
  • 0 Score
  • 1 Answer
  • Tags:   reactjs

1 Answered Questions

How to add connect with todo list item component

2 Answered Questions

Sponsored Content