14

Say I have a parent component like this:

function Recipe(recipe) { const [pageState, updatePageState] = useState("view"); return ( <div className="border-b-2 border-gray-300 py-2"> <div className="h-full flex-col md:flex md:flex-row md:justify-between md:items-start"> <div className="order-2 flex flex-col flex-1 px-2 h-full md:h-72 lg:h-64 md:flex-col md:justify-between md:order-1 md:w-1/2 lg:w-3/4" > <RecipeActions pageState = {pageState} triggerParentUpdate = {state => updatePageState(state)} /> </div> </div> </div> ) } 

and I have a child component below where I am trying to update pageState in the parent component. I've tried several iterations with no luck.

function RecipeActions(pageState, {triggerParentUpdate}){ const [open, moreActions] = useState(false); function editRecipe(){ triggerParentUpdate(pageState); } return( <div className="flex"> <span className={`${pageState=='view' ? 'hidden' : ''} ml-1 sm:ml-2 md:ml-1 lg:ml-2 shadow-sm rounded-md`}> <button onClick={editRecipe} type="button" className="inline-flex items-center px-3 sm:px-4 py-2 border border-gray-300 text-sm leading-5 font-medium rounded-md text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 active:text-gray-800 active:bg-gray-50 active:text-gray-800 transition duration-150 ease-in-out" > <svg className="h-5 w-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20"> <path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" /> <path fillRule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clipRule="evenodd" /> </svg> <p className="hidden sm:block sm:pl-2 md:hidden lg:block">Edit</p> </button> </span> </div> ) } 

1 Answer 1

17

I figured it out. See below for a summary:

The important pieces are to make sure that your props are being passed into your child as a single array, you should have a function when calling your function (e.g. onClick={() => triggerParentUpdate('edit')}), and when passing your update function to the child from the parent, you need something like this <RecipeActions pageState = {pageState} triggerParentUpdate = {updatePageState} />

Parent

function Recipe(recipe) { const [pageState, setPageState] = useState("view"); const updatePageState = (state) => { setPageState(state); } return ( <div className="border-b-2 border-gray-300 py-2"> <div className="h-full flex-col md:flex md:flex-row md:justify-between md:items-start"> <div className="order-2 flex flex-col flex-1 px-2 h-full md:h-72 lg:h-64 md:flex-col md:justify-between md:order-1 md:w-1/2 lg:w-3/4" > <RecipeActions pageState = {pageState} triggerParentUpdate = {updatePageState} /> </div> </div> </div> ) } 

Child

function RecipeActions({pageState, triggerParentUpdate}){ const [open, moreActions] = useState(false); return( <div className="flex"> <span className={`${pageState=='view' ? 'hidden' : ''} ml-1 sm:ml-2 md:ml-1 lg:ml-2 shadow-sm rounded-md`}> <button onClick={() => triggerParentUpdate('edit')} type="button" className="inline-flex items-center px-3 sm:px-4 py-2 border border-gray-300 text-sm leading-5 font-medium rounded-md text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 active:text-gray-800 active:bg-gray-50 active:text-gray-800 transition duration-150 ease-in-out" > <svg className="h-5 w-5 text-gray-500" fill="currentColor" viewBox="0 0 20 20"> <path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z" /> <path fillRule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clipRule="evenodd" /> </svg> <p className="hidden sm:block sm:pl-2 md:hidden lg:block">Edit</p> </button> </span> </div> ) } 

and here is another example I saw from this page

import React from 'react'; function App() { const [fruits, setFruits] = React.useState([ { id: '1', name: 'Apple', isFavorite: false }, { id: '2', name: 'Peach', isFavorite: true }, { id: '3', name: 'Strawberry', isFavorite: false }, ]); function handleClick(item) { const newFruits = fruits.map((fruit) => { if (fruit.id === item.id) { return { id: fruit.id, name: fruit.name, isFavorite: !fruit.isFavorite, }; } else { return fruit; } }); setFruits(newFruits); } return ( <div> <h3>with no styling</h3> <Basket items={fruits} onClick={handleClick} /> </div> ); } function Basket({ items, onClick }) { return ( <ul> {items.map((item) => ( <li key={item.id}> {item.name} <button type="button" onClick={() => onClick(item)}> {item.isFavorite ? 'Unlike' : 'Like'} </button> </li> ))} </ul> ); } export default App; 
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks this was very useful I was looking for exactly this!
This is such an elegant way of doing it. Not sure why something like this is missing from the docs.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.