I am trying to learn typescript with react and I am pretty confused right now, how will I setState of an interface? My code example:
interface Props {
children: ReactNode | ReactNode[];
}
export interface IMovie {
title: string;
video: boolean;
poster_path: string;
}
export const MoviesContext = createContext<IMovie[] | undefined>([]);
export const MoviesProvider = ({ children }: Props): JSX.Element => {
const [movies, setMovies] = useState<IMovie[]>();
return (
<MoviesContext.Provider value={[movies, setMovies]}>
{children}
</MoviesContext.Provider>
);
};
The error I get is "Type (ΙΜovie[] | Dispatch> | undefined>> is not assignable to type IMovie[]"
any other suggestions on what to change on my code welcomed. :)
To Fix define TypeScript type for a setState function when React. Dispatch<React. SetStateAction<string>> not accepted, You should set type of setValue inside IDatePickerProps to: setValue : React. Dispatch<React.
The setState() Method State can be updated in response to event handlers, server responses, or prop changes. This is done using the setState() method. The setState() method enqueues all of the updates made to the component state and instructs React to re-render the component and its children with the updated state.
To type the useState hook as an object in React, use the hook's generic, e.g. const [employee, setEmployee] = useState<{name: string; salary: number}>({name: '',salary: 0}) . The state variable will only accept key-value pairs of the specified type.
Syntax: We can use setState() to change the state of the component directly as well as through an arrow function. Example 1: Updating single attribute. We set up our initial state value inside constructor function and create another function updateState() for updating the state.
TypeScript has a generic definition for React useState according to the TypeScript React documentations. Here, S is a generic type. It accepts an initial state, and the hook can accept the state indicated by S and a setState function of type Dispatch<SetStateAction<S>>.
The setState() schedule changes to the component’s state object and tells React that the component and its children must rerender with the updated state: // Correct this.setState({name: 'Obaseki Nosa'}); React intentionally waits until all components call setState() in their event handlers before rerendering.
React makes it easy to build user interfaces and TypeScript type checks all of the JavaScript to help prevent errors. In this article, we will take a look at how to use the most popular and useful React hook, useState, with TypeScript.
Whenever the state changes, React re-renders the component to the browser. Before updating the value of the state, we need to build an initial state setup. Once we are done with it, we use the setState () method to change the state object. It ensures that the component has been updated and calls for re-rendering of the component.
The issue here is the value type that your context is defined with is IMovie
, where as the type being passed to your context during rendering is actually an array: [movies, setMovies]
.
One solution would be to define and use a prop interface with your provider, that carries both the movies
state as well as the setter for movies like this:
export interface IMovieProviderProps {
movies? : IMovie,
setMovies : (movies:IMovie) => void,
}
This IMovieProviderProps
interface would then be used to define the shape of your context value, which would provide the means for accessing the movies
state as well as updating it, from outside the provider:
/* Define context with new provider props */
export const MoviesContext = createContext<IMovieProviderProps>(null);
export const MoviesProvider = ({ children }: Props): JSX.Element => {
const [movies, setMovies] = useState<IMovie>();
/* Define provider value. Can be done inline, but I've defined
it here for clarity */
const providerValue : IMovieProviderProps = {
movies,
setMovies
}
/* Pass providerValue to provider */
return (<MoviesContext.Provider value={providerValue}>
{children}
</MoviesContext.Provider>);
};
/* Define a hook for this provider, that allows the provided value
to be consumed */
export const useMovies = () => useContext(MoviesContext);
The useMovies
hook allows the provider value to be accessed from elsewhere in your project, and can be used like this:
const ExampleComponent = () => {
/* Imported useMovies hook defined with provider above, and
extract the movies state, and movies setter base on the shape
of IMovieProviderProps */
const { movies, setMovies } = useMovies();
return <>
{JSON.stringify(movies)}
<button onClick={() => setMovies(null)}>Set Movies</button>
</>
}
A key thing to note now is that the context now exposes an object value with the shape of IMovieProviderProps
rather than an array value (as your code may have been expecting).
Hope that helps!
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