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>
)
}
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.
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) => !
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.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With