'Typescript useState: SetState in Child with argument
thx for any help.
How can I pass down setState to a child component and use the c argument without a typescript error?
Parent: Passing down setState
export interface State {
value1: string;
value2: string;
}
const Parent = () => {
const [state, setState] = useState<State>({
value1: "test",
value2: "test",
});
return (
<React.Fragment>
<Child setState={setState} />
</React.Fragment>
);
};
export default Parent;
Child: use setState with c as argument, c is read underlined with a type error
type Props = {
setState: Dispatch<State>;
};
const Child: React.FC<Props> = ({ setState }) => {
return (
<React.Fragment>
<button
onClick={() => {
//c is read underlined: Argument of type '(c: any) => any' is not assignable
//to parameter of type 'State'.
//Type '(c: any) => any' is missing the following properties from type
//'State': value1, value2
setState((c) => {
return {
...c,
value2: "HelloWorld",
};
});
}}
/>
</React.Fragment>
);
};
export default Child;
Solution 1:[1]
try this
type Props = {
setState: React.Dispatch<React.SetStateAction<any>>;
};
Solution 2:[2]
To start with, since you're using functional components, you should separate state into separate variables, rather than have a single state object. Rather than { value1: string; value2: string; }
, make two separate calls to useState
. This will simplify logic later.
const Parent = () => {
const [value1, setValue1] = useState('test');
const [value2, setValue2] = useState('test');
return (
<React.Fragment>
<Child setValue2={setValue2} />
</React.Fragment>
);
};
(Note that Parent
doesn't need a separate type declaration for State
, since it can be inferred automatically)
The key is to type the setValue2
prop in the child properly. If you hover over the setValue2
in the parent, you'll see that its type is:
React.Dispatch<React.SetStateAction<string>>
So that's what you need the Child
to have for it:
const Child = ({ setValue2 }: { setValue2: React.Dispatch<React.SetStateAction<string>> }) => {
return (
<React.Fragment>
<button
onClick={() => {
setValue2('HelloWorld');
}}
/>
</React.Fragment>
);
};
Solution 3:[3]
This
type ChildrenProps = {
setState: (value: State) => void
}
Or more prefered by me:
interface ChildrenProps {
setState: (value: State) => void
}
Most accurate, but impossible to remember:
import { Dispatch, SetStateAction} from "react"
interface ChildrenProps {
setState: Dispatch<SetStateAction<string>>
}
If you hover over your setState
function of your parent component, you will see a type like this Dispatch<SetStateAction<string>>
which you can use just like in Drew Cordanos answer.
For me that type is hard to remember. Luckily typescript is clever and also accepts a simplified form: (value: State) => void
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Drew Cordano |
Solution 2 | |
Solution 3 | Jingyi Wang |