Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Good approach to managing nested state in React

Tags:

reactjs

EDIT: I rewrote this question to clarify what I'm after - thank you to the people who have responded so far helping me hone it.

I am trying to understand how best to manage complex, nested state in React, while also limiting the number of times render() is called for components whose content has not changed.

As background:

Suppose I have state with both "authors" and "publications" in an object like this:

{
  'authors' : {
    234 : {
      'name' : 'Alice Ames',
      'bio' : 'Alice is the author of over ...',
      'profile_pic' : 'http://....'
    },
    794 : {
      'name' : 'Bob Blake',
      'bio' : 'Hailing from parts unknown, Bob...',
      'profile_pic' : 'http://....'
    },
    ...more authors...
 },
 'publications' : {
    539 : {
      'title' : 'Short Story Vol. 2',
      'author_ids' : [ 234, 999, 220 ]
    },
    93  : {
      'title' : 'Mastering Fly Fishing',
      'author_ids' : [ 234 ]
    },
    ...more publications...
  }
}

In this contrived example the state has two main areas, accessed by the authors and publications keys.

The authors key leads to an object keyed on an ID of the author, which leads to an object with some author data.

The publications key leads to an object keyed on the ID of the publication that has some publication data, and an array of authors.

Suppose my state is in an App component with child components like the following pseudo JSX:

...
<App>
  <AuthorList authors={this.state.authors} />
  <PublicationList authors={this.state.authors} publications={this.state.publications} />
</App>
...

...
class AuthorList extends React.Component {
  render() {
    let authors = this.props.authors;
    return (
      <div>
        { Object.keys( authors ).map( ( author_id ) => {
          return  <Author author={authors[author_id]} />;
        }
      </div>
    );
  }
}
...

...
class PublicationList extends React.Component {
  render() {
    let publications = this.props.publications;
    let authors = this.props.authors;
    return (
      <div>
        { Object.keys( publications ).map( ( publication_id ) => {
          return  <Publication publication={publications[publication_id]} authors=authors />;
        }
      </div>
    );
  }
}
...

Assume AuthorList has a bunch of child Author components, and PublicationList has a bunch of child Publication components that render the actual content of those things.

Here is my question: Suppose I want to update the bio for a given author, but I don't want render() to be called for all the Author and Publication objects whose content have not changed.

From this answer:

ReactJS - Does render get called any time "setState" is called?

A React component's render() function will get called any time its state, or the state of any of its parents, change - regardless of whether that state change has anything to do with the props of that component. This behavior can be changed with shouldComponentUpdate.

How people handle complex state like the above - it doesn't seem like calling render() on large numbers of components on every state change is a good solution (even if the resulting rendered object is the same and so no change occur to the actual DOM).

like image 311
deadcode Avatar asked Nov 22 '16 01:11

deadcode


People also ask

What is the best way to manage state in React?

Which state management is best in React? React's useState is the best option for local state management. If you need a global state solution, the most popular ones are Redux, MobX, and built-in Context API. Your choice will depend on the size of your project, your needs, and your engineers' expertise.

Should you use nested state in React?

Currently you shouldn't want to work with nested state in React. Because React is not oriented to work with nested states and all solutions proposed here look as hacks. They don't use the framework but fight with it. They suggest to write not so clear code for doubtful purpose of grouping some properties.

How do I use nested state in React?

To update nested properties in a state object in React: Pass a function to setState to get access to the current state object. Use the spread syntax (...) to create a shallow copy of the object and the nested properties. Override the properties you need to update.

What is the best method to update state in component React?

To update our state, we use this. setState() and pass in an object. This object will get merged with the current state. When the state has been updated, our component re-renders automatically.


1 Answers

Here is a way to accomplish this efficiently and in a readable way using Object Spread Syntax.

let state = {
    authors : {
        ...this.state.authors, 
        [ givenId ] : { 
            ...this.state.authors[ givenID ], 
            bio : newValue 
        }
    }  
}
this.setState(state)

Please remember that you have to pass a 'key' as a prop when you map items in jsx.

This is mainly because, reconciliation ( React's "diffing" algorithm to check what has changed ) thing that react does checks keys for mapped jsx ( roughly naming it jsx ).

Anyway, managing state in reacts state/setState or in redux is irrelevant to 'reconciliation'.

In both cases, you could change the part of a nested data using 'Object Spread Syntax' syntax.

All you would care about the rest is to pass 'identical' keys to the mapped jsx. So that, although react rerenders, it does not try to make dom updates to unnecessary parts, which is expensive.

like image 142
FurkanO Avatar answered Nov 15 '22 22:11

FurkanO