13

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. :)

1 Answer 1

20

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!

Sign up to request clarification or add additional context in comments.

10 Comments

I try to use your example, at "const providerValue: IMovieProviderProps = { movies, setMovies }; " I get an error Type 'IMovie | undefined is not assignable to type IMovie
Sorry missed the ? on provider props - does that help?
yeah that gives no errors but could you give me an example on how to use this in a component to setState const providerValue = useContext<IMovieProviderProps | null>(MoviesContext);
Just extended answer - let me know if you need any more help :-)
thanks for this, but I have a couple of questions. First of all this " const [movies, setMovies] = useMovies() gives me an error " Property movies does not exist on type IMovieProviderProps | null" and I have to do something like this "const providerValues = useMovies();" and then providerValues?.movies. Second question cause I am begginer and I am confused. I want movies to be an array of object so provider needs useState<IMovie[]> ?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.