NevilleS
NevilleS

Reputation: 1209

Managing nested Redux containers without passing props?

Given a component hierarchy like this:

<TodoList>
  <Todo>
    <TodoHeader/>
    <TodoBody>
      <TodoDetails>
        <TodoStatus />
      <TodoDetails>
      <TodoDescription />
    <TodoBody>
  <Todo>
</TodoList>

...and a store like this:

{
  todos: [
    { id: 1, status: "INCOMPLETE", header: "title one", description: "do a something" },
    { id: 2, status: "INCOMPLETE", header: "title two", description: "something else" },
    { id: 3, status: "COMPLETE", header: "title three", description: "one more thing" },
  ]
}

Is there a good way for the nested TodoStatus component to connect to the store without having to pass the id down the component hierarchy as props? For example, Todo could set currentTodoId = 1 as context, which would be available for child reducers, but are there alternatives to that? Maybe a way for the parent component to reduce the store down to a single todo that child components would then be able to see...?

At this point, you're probably wanting to ask "why"? Well, consider that there may be several levels of strictly presentational components in between the TodoList (which is operating on the array of todos) and the nested TodoStatus (which only wants to operate on a single todo). Having to pass the todoId down through a hierarchy like this is pretty painful:

<TodoList>
  <Todo todoId={1}>
    <SomeAnimation todoId={1}>
      <SomeLayout todoId={1}>
        <SomeOtherAnimation todoId={1}>
          <SomeDebugContainer todoId={1}>
            <TodoHeader todoId={1}>
            <TodoBody todoId={1}>
              <TodoDetails todoId={1}>
                <TodoStatus todoId={1}> // yay!

At this point, I'm imagining that this is specifically what React context is good for, so there's probably not a Redux-specific pattern, but I'd like to be wrong!

Upvotes: 3

Views: 890

Answers (2)

Dan Abramov
Dan Abramov

Reputation: 268333

Why do they all need to accept id as an argument?

Usually some component higher in the hierarchy (e.g. Todo) would accept either id or todo, but the components below would be more specific in what they accept, e.g.

function Todo({ todo }) {
  return (
     <SomeAnimation>
        <SomeLayout>
          <SomeOtherAnimation>
            <SomeDebugContainer>
              <TodoHeader title={todo.title} />
              <TodoBody {...todo} />
            </SomeDebugContainer>
          </SomeOtherAnimation>
        </SomeLayout>
     </SomeAnimation>
  )
}

In this example, TodoHeader just receives a title prop directly. If it needs more props, you can spread over todo properties with {...todo} like I do in <TodoBody>. It is not obvious from your example why components like SomeAnimation would need to know the todo ID either—presumably passing some visual properties of it would be enough.

Similarly, inner components like TodoBody might pass some of their props down, but again, this doesn’t have to be the ID:

function TodoBody({ title, text, status }) {
  return (
    <div>
      <TodoDetails text={text} />
      <TodoStatus status={status} />
    </div>
  )
}

In general, deep trees returned from render() usually mean your component structure is suboptimal. You don’t have to use this.props.children in every component—feel free to keep components in control over their own rendering, and only pass what is necessary to them. Sometimes passing an id is convenient, other times passing data directly makes dependencies more explicit.

Upvotes: 1

Exayy
Exayy

Reputation: 640

Connect seems to be a bad idea, as you said each Todo is a presentation component and should ignore anything about redux store or application.

I have the same problem on a project, for the moment I think it seems painful but it make each element reusable and simplify the code (not the quantity of code but the logic). May be you can simplify your dom/component structure, using react children encapsulation to limit the number of "levels"

Not sure I helped a lot. If you find a great solution I will glad to read it.

Good luck

Upvotes: 0

Related Questions