Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating Parent Component State from Child Component with UseState React Hook

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>
  )
}
like image 603
Paul DeVito Avatar asked Jun 03 '20 17:06

Paul DeVito


People also ask

How do you update parent state from child component in React hooks?

React hooks are introduced in React 16.8. If you are familiar with the class components then there is no difference to change the parent component state from child component. In both cases, you have to pass the callback function to the parent.

How do you update child state to parent component?

To change child component's state from parent component with React, we can pass props. const Child = ({ open }) => { return <Drawer open={open} />; }; const ParentComponent = () => { const [isOpen, setIsOpen] = useState(false); const toggleChildMenu = () => { setIsOpen((prevValue) => !

How do you pass data from child to parent in React hooks?

First, you'll need to create two components, one parent and one child. Next, you'll import the child component in the parent component and return it. Then you'll create a function and a button to trigger that function. Also, you'll create a state using the useState Hook to manage the data.


1 Answers

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;
like image 85
Paul DeVito Avatar answered Oct 20 '22 18:10

Paul DeVito