0

I'm trying to implement the data type returned from the API I'm using. The total_page and total_results are marked as an error. Looks like I need to implement some type. I can't understand how to solve this problem this type requirement. The message is:

(property) React.ProviderProps.value: MoviesContextData The type '{ movies: MovieData[]; pageNumber: number; setPageNumber: Dispatch<SetStateAction>; }' does not have the following properties of type 'MoviesContextData': total_pages, total_results ts(2739) index.d.ts(327, 9): The expected type comes from the 'value' property, which is declared here in the type 'IntrinsicAttributes & ProviderProps'"

import {
    useContext,
    createContext,
    useEffect,
    useState
} from "react"

import { MoviesProviderProps } from "../interfaces/props"
import { MovieData, MoviesContextData } from "../interfaces/types"

import axios from "axios"
import { POPULAR_BASE_URL } from "../services/api"

const MoviesContext = createContext<MoviesContextData>(
    {} as MoviesContextData
)

export const MoviesProvider = ({ children }: MoviesProviderProps) => {
    const [movies, setMovies] = useState<MovieData[]>([])
    const [pageNumber, setPageNumber] = useState(1)
    const [totalResults, setTotalResults] = useState(0)
    const [currentPage, setCurrentPage] = useState(1)

    const nextPage = ({ pageNumber }: MoviesContextData) => {
       axios.get(`${POPULAR_BASE_URL}&page=${pageNumber}`)
    }

    useEffect(() => {
        axios.get(`${POPULAR_BASE_URL}&page=${pageNumber}`)
            .then(response => {
                setMovies(response.data.results)
            })
    }, [])

    return (
        <MoviesContext.Provider value={{ movies, pageNumber, setPageNumber }}>
            {children}
        </MoviesContext.Provider>
    )

}

export const useMovies = () => {
    const context = useContext(MoviesContext)

    return context
}

Types:

  export type MoviesContextData = {
    movies: MovieData[];
    pageNumber: number;
    setPageNumber: (prevState: number) => void;
    total_pages: number;
    total_results: number;
}

export type MovieData = {
    id: number;
    backdrop_path: string;
    poster_path: string;
    title: string;
    release_date: string;
    vote_average: number;
}
5
  • Your value is incorrect, value={{ movies, pageNumber, setPageNumber }} compared to the type you've specified (more details in the answer below). But you should be very careful when writing out a context value this way. You are effectively creating a new object on every render of this parent. Which then means that any child will also re-render. Can be a noticeable performance issue. Maybe look at memoizing this object before passing it as a value const value = useMemo(() => ({...}), [...]) Commented May 2, 2022 at 17:19
  • I find it strange that you use two different naming semantics for your variables inside MoviesContextData. Why use camelCase and snake_case in a model you can control? Commented May 2, 2022 at 17:25
  • Sorry, I didn't quite understand what you meant. Commented May 2, 2022 at 17:29
  • I used it this way because the data is exactly like this in the API Commented May 2, 2022 at 17:30
  • What I mean is the MovieData that you get from the API is understandable. But you're creating the context and passing total_pages and pageNumber through. It would be better to be consistent in your casing. Commented May 2, 2022 at 20:01

1 Answer 1

1

You define MoviesContextData as:

export type MoviesContextData = {
    movies: MovieData[];
    pageNumber: number;
    setPageNumber: (prevState: number) => void;
    total_pages: number;
    total_results: number;
}

And then you provide this value for that type:

<MoviesContext.Provider value={{ movies, pageNumber, setPageNumber }}>

total_pages and total_results are required properties, but are missing in the context provider's value.

That's what this portion of that error message is trying to tell you:

does not have the following properties of type 'MoviesContextData': total_pages, total_results ts(2739)


To fix it you need to provide those properties with something like:

<MoviesContext.Provider value={{
  movies,
  pageNumber,
  setPageNumber,
  total_pages: Math.ceil(totalResults / numberOfResultsPerPage),
  total_results: totalResults
}}>

Or make the properties optional:

export type MoviesContextData = {
    // other properties...
    total_pages?: number;
    total_results?: number;
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you! But if I add these two properties in the context provider, an error appears asking to initialize. What does that mean? This appears here: "There is no in-scope value for the shorthand property 'total_pages'. Declare one or provide an initializer."
{ movies } is shorthand for { "movies": movies } and only works if you have a local variable named movies. So you have to provide a for those property names in the context value. I don't know how you system would tell you the total pages, I just guessed with some made up math. You are going to figure out how to provide those values.
Alex, do you mean that the correct thing would be for me to put the type 'MoviesContextData' in all states related to that type? So I would put the state value as the value of the respective variable that is in the context provider?
What I mean is that when you have context declared with the type MoviesContextData, then you have to use a value for that context that is an object that fully implements the MoviesContextData type. And that means that it has all required properties from that type.

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.