Yes, as far as passing down props are concerned there is no difference in usage with React Hooks. In the snippet you've provided just pass setSearchData as a prop to PostContainer.
<PostContainer
data={dataOnMap}
addLike={addLike[index]}
searchData={searchData}
setSearchData={setSearchData}
/>
Answer from Deniz Tetik on Stack OverflowYes, as far as passing down props are concerned there is no difference in usage with React Hooks. In the snippet you've provided just pass setSearchData as a prop to PostContainer.
<PostContainer
data={dataOnMap}
addLike={addLike[index]}
searchData={searchData}
setSearchData={setSearchData}
/>
Yes Absolutely you can. In fact React docs talk about "Lifting state up" so to speak.
If there is shared state between components and you need to lift it up to their nearest ancestor.
The general concept is props are passed down and state is passed up.
However, this can get messy. If you are working on a larger project, I would recommend using Redux.
You can pass the state as props, but if you want child components to alter state, then you can pass the setter from the useState directly to child components.
Here is the same example:
<PostContainer
data={dataOnMap}
addLike={addLike[index]}
searchData={searchData}
setSearchData={setSearchData}
setAddLike={setAddLike}
/>
Or another solution
const LikeManager = {
addLike: setAddLike,
data: {
//some data
}
}
<PostContainer
data={dataOnMap}
likeManager: {LikeManager}
/>
I know this is not part of the question, but I would recommend using scalar values for useState wherever possible
Side note: I really wish the documentation was updated away from the class system. It seems like everyone has moved to hooks at the time of me learning react and the most valuable resource is hard to navigate due to that. It seems there are a many ways to pass state, and props across components, this is by far the most confusing to me current.
//App.js
function App(){
const [count, setCount] useState=(0); return(
<div>
<Child setCount={setCount}/>
</div>
)
}
//Child.js
const Child = () => {
function incrementCount(){
setCount(count +1) }
return(
<div>
<button onClick={decrementCount}> - </button>
<span>{count}</span>
</div>
)
}Now my problem is, how do I give my child component access to “count” from my hook in app? I want to be able to define my functions away from app but give them access to state when I write them. <Child setCount={setCount} count={count}/> only works for setCount but when I put count like that it says “count not declared” and I cant access count in my child component functions.
Videos
you can pass the modalOpen and handleState separately like this
<Modal
mg={therapies[0].img}
imgAlt={therapies[0].imgAlt}
title={therapies[0].title}
info={therapies[0].info}
isOpen={modalOpen}
toggleModal={handleState}
/>
and use it in Modal component as
const Modal = ({ img, imgAlt, title, info, isOpen, toggleModal }) => {
<Button
onClick={() => {
if (isOpen) {
toggleModal(false);
}
}}
you don't actually need to pass modalOpen and handleState separately.
It should work anyway.
Plus, you dont need to define a new method to set the setter function. below is totally unnecessary.
const handleState = (e) => {
setModalOpen(e);
};
https://codesandbox.io/s/pass-usestate-to-child-c0qx6
A common technique for these situations is to lift the state up to the first common ancestor of all the components that needs to use the state (i.e. the PageComponent in this case) and pass down the state and state-altering functions to the child components as props.
Example
const { useState } = React;
function PageComponent() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1)
}
return (
<div className="App">
<ChildComponent onClick={increment} count={count} />
<h2>count {count}</h2>
(count should be updated from child)
</div>
);
}
const ChildComponent = ({ onClick, count }) => {
return (
<button onClick={onClick}>
Click me {count}
</button>
)
};
ReactDOM.render(<PageComponent />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
You can create a method in your parent component, pass it to child component and call it from props every time child's state changes, keeping the state in child component.
const EnhancedTable = ({ parentCallback }) => {
const [count, setCount] = useState(0);
return (
<button onClick={() => {
const newValue = count + 1;
setCount(newValue);
parentCallback(newValue);
}}>
Click me {count}
</button>
)
};
class PageComponent extends React.Component {
callback = (count) => {
// do something with value in parent component, like save to state
}
render() {
return (
<div className="App">
<EnhancedTable parentCallback={this.callback} />
<h2>count 0</h2>
(count should be updated from child)
</div>
)
}
}
The type that would match the function returned from invoking useState would be:
setMyVar: (value: boolean | ((prevVar: boolean) => boolean)) => void;
If we look at the type definition file from DefinitelyTyped [1], we can see that the second type in the return type is a dispatch:
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
Thus the generic type provided is passed through to SetStateAction<S>, which is defined as:
type SetStateAction<S> = S | ((prevState: S) => S);
So essentially, an interface for your component would be the following:
interface IProps {
myVar: boolean;
setMyVar?: (value: boolean | (prevVar: boolean) => boolean) => void;
}
As @Retsam said, it's best to use React's exported types:
import { Dispatch, SetStateAction } from "react";
interface IProps {
myVar: boolean;
setMyVar?: Dispatch<SetStateAction<boolean>>;
}
References: [1] https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L845
Dispatch & SetStateAction types
As @Retsam mentioned, you can also import and use the types Dispatch and SetStateAction from React:
import React, { Dispatch, SetStateAction } from 'react';
const MyChildComponent1 = (
myVar: boolean,
setMyVar: Dispatch<SetStateAction<boolean>>
) => {...};
Bonus
When I find myself frequently using this, I create a type alias to help with readability
import React, { Dispatch, SetStateAction } from 'react';
type Dispatcher<S> = Dispatch<SetStateAction<S>>;
const MyChildComponent1 = (
myVar: boolean,
setMyVar: Dispatcher<boolean>,
) => {...};
hope this helps.