简体   繁体   中英

How to update parent's component using state from child component in React?

I have 3 components.

In ListCard.js, I map cards array and based on the card the user click on, I call handleChangeCardData to update the modal's text.

My question is: How do I update/change the modal's text when my handleChangeCardData function is inside ListCard.js and my modal is on the same level. (Both are in Board.js)

Board.js

const [cardTitle, setCardTitle] = useState("");
return (
     {columns.map((column, index) => (
            <div className="column__container" key={index}>
              <div className="column__header">
                <div className="columnHeader__name">
                  <p>{column.name ? column.name : "..."}</p>
                </div>
                <div className="columnHeader__button">
                  <button
                    className="btn btn-sm --create-card-btn"
                    data-bs-toggle="modal"
                    data-bs-target="#modal-card"
                    onClick={() => setColumnId(column.id)}
                  >
                    New item
                  </button>
                </div>
              </div>
              <Droppable droppableId={column.id}>
                {(provided, snapshot) => (
                  <div
                    className="column"
                    ref={provided.innerRef}
                    {...provided.droppableProps}
                  >
                    <ListCard columnId={column.id} />
                    {provided.placeholder}
                  </div>
                )}
              </Droppable>
            </div>
          ))}
    <ViewCardModal cardTitle={cardTitle} />
)

LisCard.js

const handleChangeCardData = (cardTitle) => {
    setCardTitle(cardTitle);
  }

return (
{cards.map((card, index) => (
        <>
        <div key={index}>
          <Draggable draggableId={card.id} index={index}>
            {(provided, snapshot) => (
              <div
                ref={provided.innerRef}
                {...provided.draggableProps}
                {...provided.dragHandleProps}
              >
                <div
                  className="card --listcard-card"
                  onClick={() => handleChangeCardData(card.title)}
                  data-bs-toggle="modal"
                  data-bs-target="#modal-card-details"
                  style={{ border: `2px solid ${card.color}` }}
                >
                  <div className="card-body">
                    <p>{card.title}</p>
                  </div>
                </div>
              </div>
            )}
          </Draggable>
        </div>
        </>
      ))}
)

ViewCardModal.js

function ViewCardModal(props) {
    return (
        <div>{props.cardTitle}</div>
    )
}

In general, lift state up . In this case, it sounds like that means moving the state into Board and then passing that state to whatever child components need it (as a prop), and the state setter to whatever (other) child components need it.

Here's a minimal example of lifting state up. I haven't tried to recreate the full complexity of your example, just to provide an example of Parent having state that ChildA uses and ChildB sets:

 const {useState} = React; const ChildA = React.memo(({counter}) => { console.log("ChildA rendered"); return <div>Counter = {counter}</div>; }); const ChildB = React.memo(({setCounter}) => { console.log("ChildB rendered"); return <input type="button" value="Increment Counter" onClick={() => setCounter(c => c + 1)} />; }); const Parent = () => { const [counter, setCounter] = useState(0); return ( <div> <ChildA counter={counter} /> <ChildB setCounter={setCounter} /> </div> ); }; ReactDOM.render(<Parent />, document.getElementById("root"));
 <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.development.js"></script>

If there are several levels of hierarchy between where the state is being held and a descendant component that needs it, you might use context instead of props (although you might also look at component composition instead). See those links for details.

you cant do that directly, but must use props.

in list:

onClick={() => props.onClick(card.title)}

in board:

 handleChangeCardData = (cardTitle) => {
    setCardTitle(cardTitle);
  }

<ListCard columnId={column.id}  onClick={(e)=>handleChangeCardData(e)}/>

Inside ListCard:

const ListCard = ({setCardTitle}) => {...}

onClick={() => setCardTitle(card.title)}

In the parent:

<ListCard columnId={column.id}  setCardTitle={setCardTitle} />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM