React - passing data to nested components

I read somewhere that it’s good practice or common to have the state in the parent most component, but the parent most component is App, right? Well there may be some cases where you don’t need to have the state in the App component. I’m wondering if having the state in App component is a good idea or something that React developers usually do.

I ask this because in the app that I’m currently building I might need to lift the state up to the parent most component (App) to be able to pass data to all children. BUT, doing so means that I will also need to go 2 levels of nesting, for example:

class App extendes Component {
 render() {
 <React.Fragment>
  <main className="container">
    <FirstLevel data={this.state.mainData} moreData={this.state.moreData} />
  </main>
</React.Fragment>
 }
}

And the FirstLevel component has another component that also needs data from state:

const FirstLevel = props => {
 return (
  <div>
   <p>This is first level child</p>
    <SecondLevel moreData={this.props.moreData} />
  </div>
 );
}

It’s easy to see why things can get messy here, I use Sass I know we shouldn’t go beyond 3 level of nesting. I’d like to know what level of nesting would be considered bad practice in React or if the example above is fine but I shouldn’t nest deeper than that.

Have you looked at Redux?

1 Like

No, not yet. I want to feel comfortable with React before jumping to Redux.

Well this sort of situation is where a state manager like Redux helps. Of course it is still possible to manage state in your main app.

Before learning Redux, I’d learn the vanilla React way to handle it. Yes, Redux is awesome, but you still need to understand basic React.

You should keep state in the parent-est app of everything that needs state. Not every component will need state. Also keep in mind that some components might have their own state for things that only they need (like inputs).

This is an old pen I wrote on data passing. You send data from parent to child with props, and you send data from child to parent with a callback that the parent sends the child as a prop. To do it with a deeper level, you just keep passing, the prop gets sent from the parent to the child to the grandchild. In the other direction, the grandchild calls the callback that the child sent as a prop that the child received as a prop from the parent.

Yes, it gets messy. That’s why we like Redux. But this pattern will still show up so you need to understand how it works. I use Redux all the time, but there are definitely times when I still need to pass props and callbacks for code clarity and to use certain libraries. You need to understand how that works.

3 Likes

That’s how I feel, I want to learn React and I want to learn it well before jumping to other libraries.

When I first designed my app I didn’t think I should’ve had the state in the parent most component (App) as I thought I didn’t need to send data from App to other children, but now I reached a point where I need to send data from App to one its child component.

I could lift the state up to the App component and refactor everything, but I would go 2 levels of nesting, even 3 I think… Does not look like a good idea. I think I’ll be better off by just creating a function that gets the piece of data I need from my stateful component and lift it up to the App component and then just take it from there. Everything remains the same, I avoid possible bugs and well, lesson learned. Next time I should have the state in the App component.

From Dan Abramov, the guy who invented Redux:

However, if you’re just learning React, don’t make Redux your first choice.

Instead learn to think in React. Come back to Redux if you find a real need for it, or if you want to try something new.

As far as I can tell, the point when you need Redux is when your app’s complexity reaches a point that:
(pain of Using Redux) < (pain of managing a state that marches up and down the component tree like a colony of ants)

1 Like

You should put it in the node that is the first common node to all components that need the app state. This may be App or may be one of it’s children or even grandchildren, depending on how things are organized. Remember that every class component will have it’s own state that you may or may not use for local things.This is differnet than what you have decided to use as the app state (it took me a while to understand this.) Passing data two or three or even more levels is not uncommon in a React app. When that starts driving you crazy, you’ll be ready for Redux.

But as pointed out, sometimes you don’t need Redux and on simple apps, I may just do it without Redux. Even when I’m using Redux I may still pass data/callbacks because I want a component to be “dumb” like in the container/presentaional model. You can still do that with Redux, but the container component is wired into Redux and the “dumb” presentational component just gets passed data and callbacks. You don’t need to understand all that yet, but I’m just saying that these (frustrating) skill are not useless.

Organizing these apps takes practice. But understanding this is part of React. If you need to, draw out your component tree. Eventually you’ll just get an intuition for it.

Oh really? I thought there was some rule out there about avoiding passing data 2 or 3 levels deep that everyone was following and therefore doing such was considered bad practice. You say it’s not uncommon, but is it good practice though? I’m new to React but I already can see why passing data up to 3 levels (or more) could become an annoyance for maintainability reasons.

I’m facing this problem simply because at the beginning I didn’t think I was going to implement routing to my app, that’s why I saw no need to have the state in the App component because as you said, I put the state in the node that was the first common to all other components. But now I decided to implement routing and need to pass data, knowing from the very beginning what you want to do definitely helps.

I also try to work with stateless functional components as much as possible and keep a single source of truth, I think it’s easier (especially for a noob like me) to work with, things can get confusing having states here and there. However I do understand that for certain components (forms come to my mind) is better to have local states, this way they can be reusable.

On a side note, how can I avoid this repetition?

render() {
    const {
      moviesData,
      genres,
      pageSize,
      currentPage,
      selectedGenre,
      searchQuery,
      sortValue,
      loading,
      bounce
    } = this.state;

    let allMovies = moviesData.popularMovies;

    if (sortValue === "Top Rated") {
      allMovies = moviesData.topRatedMovies;
    } else if (sortValue === "Now Playing") {
      allMovies = moviesData.theaterMovies;
    }

moviesData is an object with 3 value keys, is there way to use destructuring and get the keys of this object so I don’t have to write “moviesData.” every time I want a property of that object?

Two or three is not a big deal. On the massive app I work on at work, there are often 15-20 levels deep in the component structure. Obviously we use Redux for that. But there are time when local state is passed to children and grandchildren.

You definitely have to be careful with it. But with this app, if you don’t have Redux and you want a useful component structure, you may have to learn how to pass things 2, 3, or even 4 levels deep. This is good training. It is not ideal practice. In the real world at that point you’d want Redux of Mobx or Flux or some other state management.

Yes, as the old saying goes, “Days of debugging (or refactoring) will save you hours of planning.”

“I also try to work with stateless functional components as much as possible…”

Good idea in principle.

“… and keep a single source of truth”

A common expression in Redux, but it can apply here as well.

“However I do understand that for certain components (forms come to my mind) is better to have local states, this way they can be reusable.”

A good example. Some people still chose to handle that in Redux, but using local state is a perfectly cromulent choice as well.

“moviesData is an object with 3 value keys, is there way to use destructuring and get the keys of this object so I don’t have to write “moviesData.” every time I want a property of that object?”

Sure, destructuring is a perfect tool for that. Have you tried

const { popularMovies, topRatedMovies, theaterMovies } = moviesData;
let allMovies = popularMovies;
// ...

You might also get away with

const { popularMovies: allMovies, topRatedMovies, theaterMovies } = moviesData; 
// ...

depending on what the data is and how you need the variables later on.

All right sounds good, I think I will just lift the state up to the parent most component, refactor my code and pass data up to all components. As you mentioned I think it’s a good training for me to learn how to work with situations like this, better sooner than later. And yes it’s not a big deal for me because I know exactly where to go to pass the data, I guess I was more curious about whether or not passing data 2/3 levels deep was considered bad practice and you cleared my doubts. Thanks a lot man, hopefully when I finish the app I can get some feedback :wink:

Yeah, passing 2/3 levels is definitely to be avoided once you’re in the “real world”. But it might happen if you have a simple app and you don’t want to bother with a state manager. Even with Redux, I can think of at least one instance where I had to do it for a generic component that was getting all over the app.

Ok another thing, I read somewhere that passing too many props to a component is not a good practice, if I am going to refactor my code I just realized that I might to pass like 8/9 props to the component that used to be my stateful component. Would this be bad…? I mean I didn’t design my app having in mind that App would be my stateful component, now I have to deal with this mess.

I don’t know about that. It really depends on what you need. If there are that many props, then maybe some of them should be wrapped in an object. Or maybe the component is trying to do too much. But if you’re not using state management, then maybe it’s just what you need. If it’s a readability thing, you can always store them in an object and then spread them:

const myProps = { 
  prop1: 1,
  prop2: 2,
  // ...
}

//...
  <MyComponent { ...myProps } />
2 Likes