javascript - Manipulating state of multiple child components - Stack Overflow

I'm not sure whether or not it is best to keep state within the individual child ponent or the par

I'm not sure whether or not it is best to keep state within the individual child ponent or the parent.

I have a parent ponent which will hold a child ponent which needs to be able to be duplicated on demand.

I have a few questions:

  • Where do i store the state for the individual ponent is it in the ponent itself or is it in the parent?

  • If it is in the child ponent how do I tell the parent to update the other children.

  • If it's in the parent how do I pass a function to the child which will update ITS state and not the parents state?

  • How do I access each of the ponents state and tell it to change based on another child state changing?

Currently I'm pushing a new "card" Component into an array which keeps track of all the Components I need to render on the "board".

I can't conceptualise the best way to manage the state of everything and how to access each child. Do they have an individual ID? how can I change all their states.

  • --------------------- BOARD ----------------------- *
    import React from "react";
    import Card from "./Card";

    export default class Board extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          cards: [<Card />]
        };
      }

      ponentDidMount() {}

      createCard() {
        this.state.cards.push(<Card />);
        this.forceUpdate();
      }

      render() {
        return (
          <div id="Board">
            <button onClick={() => this.createCard()}>Create Card</button>
            {this.state.cards.map(card => (
              <Card />
            ))}
          </div>
        );
      }
    }
  • -------------------------- CARD ------------------------------ *
 export default class Card extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
       active: false
     };
   }

   cardClick = () => {
     this.setState({
       active: !this.state.active
     });
   };

   render(cardClick) {
     return (
       <div>
         {this.state.active ? (
           <div
             className="activeCard"
             id="card"
             onClick={() => this.cardClick()}
           >
             Active
           </div>
         ) : (
           <div
             className="inactiveCard"
             id="card"
             onClick={() => this.cardClick()}
           >
             Inactive
           </div>
         )}
       </div>
     );
   }
 } ```



I'm not sure whether or not it is best to keep state within the individual child ponent or the parent.

I have a parent ponent which will hold a child ponent which needs to be able to be duplicated on demand.

I have a few questions:

  • Where do i store the state for the individual ponent is it in the ponent itself or is it in the parent?

  • If it is in the child ponent how do I tell the parent to update the other children.

  • If it's in the parent how do I pass a function to the child which will update ITS state and not the parents state?

  • How do I access each of the ponents state and tell it to change based on another child state changing?

Currently I'm pushing a new "card" Component into an array which keeps track of all the Components I need to render on the "board".

I can't conceptualise the best way to manage the state of everything and how to access each child. Do they have an individual ID? how can I change all their states.

  • --------------------- BOARD ----------------------- *
    import React from "react";
    import Card from "./Card";

    export default class Board extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          cards: [<Card />]
        };
      }

      ponentDidMount() {}

      createCard() {
        this.state.cards.push(<Card />);
        this.forceUpdate();
      }

      render() {
        return (
          <div id="Board">
            <button onClick={() => this.createCard()}>Create Card</button>
            {this.state.cards.map(card => (
              <Card />
            ))}
          </div>
        );
      }
    }
  • -------------------------- CARD ------------------------------ *
 export default class Card extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
       active: false
     };
   }

   cardClick = () => {
     this.setState({
       active: !this.state.active
     });
   };

   render(cardClick) {
     return (
       <div>
         {this.state.active ? (
           <div
             className="activeCard"
             id="card"
             onClick={() => this.cardClick()}
           >
             Active
           </div>
         ) : (
           <div
             className="inactiveCard"
             id="card"
             onClick={() => this.cardClick()}
           >
             Inactive
           </div>
         )}
       </div>
     );
   }
 } ```



Share Improve this question edited Jan 28, 2019 at 3:36 Christopher asked Jan 28, 2019 at 3:32 ChristopherChristopher 832 silver badges12 bronze badges 7
  • Please format your code properly, just selecting it and hitting ctrl + k or cmd + k on a Mac will do the trick! – Predrag Beocanin Commented Jan 28, 2019 at 3:35
  • Thanks sorry i added in the code block but it didn't format! =) – Christopher Commented Jan 28, 2019 at 3:37
  • I don't understand your 3rd question, why would you need to pass a function to the child ponent to update the child? – Keno Commented Jan 28, 2019 at 3:52
  • Hey Keno my understanding was that if passed the function that toggles the state of the individual card from parent to child i'm able to then use that same function to alter the other "Cards" state as its Parent > Children. What i'm trying to achieve is initially all cards are inactive. When one card is clicked the card is active. If any other cards are active then deactivate them. – Christopher Commented Jan 28, 2019 at 3:54
  • 1 It would be far easier to simply pass a prop to each Card from the Board and then change their state depending on that prop – Keno Commented Jan 28, 2019 at 4:07
 |  Show 2 more ments

3 Answers 3

Reset to default 4

Alrighty, let's take it from the top. I imagine you have some data you want to render as <Card />, one for each data item. You don't hold the ponents in the state, but rather, data. For instance:

this.state = {
  data: [
    {value: 'Cat 1'},
    {value: 'Cat 2'},
    {value: 'Cat 3'}
  ] 
} 

In this case, it's correct for the parent to hold the data. However, the whole concept of lifting the state up (React docs link) is not all that hard. Mostly, it's the question of: does more than one ponent care/depend on the same state? If the answer is yes, usually the parent should hold it. You're correct for having each card holding its own active state. However, the the parent could do it as well. Let's do that then shall we:

Board.js

import React from 'react';
import {Card} from './Card';    

class Board extends React.Component{
    state = {
      data: [
        {value: 'Cat 1'},
        {value: 'Cat 2'},
        {value: 'Cat 3'}
      ],
      activeCard: null, 
    }
    cardClick = id => {
       this.setState({ activeCard: id })
    }
    addCard = () => {
      const newCard = { value: 'Some val here' };
      this.setState({ data: [...this.state.data, newCard] });
    }
    render(){
      return(
        <div id="Board">
          <button onClick={this.addCard}>Add a card</button>
          {this.state.data.map((item, index) => 
            <Card key={index} 
              value={item.value} 
              active={this.state.activeCard === index}
              cardClick={this.cardClick}
              index={index}
            />
           )}
         </div>
       )
    }
}

export default Board;

By doing this, our parent manages everything. Not to say it's the only right way, but this lets us have the Card ponent as a 'dumb', functional ponent. Be careful - this specific approach relies on data never changing order, since it relies on the .map index, which is from 0 to length of data - 1.

Card.js

import React from 'react';

const Card = props => (
    <div
        className={props.active ? 'activeCard' : 'inactiveCard'}
        onClick={() => props.cardClick(props.index)}
    >
        Active
    </div>
);

export { Card };

There are a few key differences between what you posted and what I've done.

1) You were mapping cards with the same id="card" which is bad, id should be unique. Also, unless you really need it, you can omit it.

2) I'm toggling the className based off of the index of the active card. If the current card, let's say 2, is also the active card, it'll have activeCard className.

3) Finally, I'm passing in a function to the child that updates the parents state. By doing this, I have the state contained to the parent, and every time I update it, it'll reflect on the children as well. That's not to say your approach of having class based ponents for Cards is wrong, but this is simpler I think.

4) Just to throw it out there, WAI-ARIA doesn't really agree with a div having onClick events. To make the Internet a cool, accessible place, you can put a role="button" on the div, to signal it's a button. That also requires it be focusable, as well as a keyboard event listener, in which case, you're probably better of just using a <button> if the element should be clickable.

To answer your other questions:

  • The parent automatically propagates all state changes to all children that care for it

  • All child ponents are independent of the parent, eg if they have their own states, the parent doesn't care. It's only when they share a state AND a state update function that this bees relevant, so only if you specifically pass such function to the children

  • If the children share a state, then it should be lift up, which is explained in the doc linked!

EDIT: for the given example, I assumed you only want one active card at a time. If that's not the case, either have each card hold their active states, like Keno Clayton suggested, or change activeCard into an array, checking index of each card against array of active cards

To answer your questions:

Where do i store the state for the individual ponent is it in the ponent itself or is it in the parent?

Best practice is to store the state in the ponent that needs it. If two sibling ponents need access to the same state then raise it to the parent.

You can then pass down individual props or pass the entire state down with the Context Api. You can use this to pass down functions to update the parent state if needed, and the children will automatically receive the props as they are updated.


For your specific scenario, each Card should have its own state to determine whether it is active or not. It would be possible to keep an array of active states in the parent as well, but that's not as intuitive and a bit more plex.

How do I access each of the ponents state and tell it to change based on another child state changing?

You shouldn't do that. You should maintain any information that you want to share with other ponents in the parent.

Where do i store the state for the individual ponent is it in the ponent itself or is it in the parent?

State of the individual ponent should be inside the ponent if that state is only controlled and needed within that ponent. For eg: active(boolean) in Card. Since a click on a card should make it selected, as well as make current active Card inactive we can conclude that it is better stored outside Card ponent in the Parent.

If it's in the parent how do I pass a function to the child which will update ITS state and not the parents state?

You can pass that function as a prop(after binding to the parent)

How do I access each of the ponents state and tell it to change based on another child state changing?

Since you keep list of cards and active boolean in parent Board ponent, you dont need to do this.

Keep a state like this in Board.

this.state = {
   cards: [
     {id: 1, name: 'Card1'},
     {id: 1, name: 'Card2'},
     {id: 1, name: 'Card3'},
   ],
   activeId: 2
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745386637a4625468.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信