Josh Simon
Josh Simon

Reputation: 259

How to type an object retrieved using useLocation?

I'm passing data as props from my Photo.tsx component to PhotoDetails.tsx, as follows:

Photos.tsx

<Link to = {`/photo/${photo.date}`} state = {photo}>
                <img src = {photo.url} />
            </Link>

The data being passed to PhotoDetails takes the following form:

{copyright: 'Jeff Graphy', date: '2022-02-28', explanation: "You don't have to look through a telescope to know…detail.  Your next chance will occur on March 17.", hdurl: 'https://apod.nasa.gov/apod/image/2202/MoonHands_Graphy_960.jpg', media_type: 'image', …}
copyright: "Jeff Graphy"
date: "2022-02-28"
explanation: ******"
hdurl: "https://apod.n*******"
media_type: "image"
service_version: "v1"
title: "*****"
url: "https://apod.nasa.gov/apod/image/2202/MoonHands_Graphy_960.jpg"
[[Prototype]]: Object

In PhotoDetails, I'm trying to extract the data passed to it by Photo, as follows:

const {state } = useLocation()
    console.log(state.url)

When I log state to the console, it gives the correct data. However when I log state.url, I get the error

Object is of type 'unknown'.

To fix this, I provided useLocation with an interface to describe the shape of the data:

interface IPhoto {
        copyright:string,
        date:string,
        explanation:string,
        hdurl:string,
        media_type:string,
        service_version:string,
        title:string,
        url:string
    }

const {state } = useLocation<IPhoto>()
    console.log(state.url)

....but then go the error

Expected 0 type arguments, but got 1.

Any ideas on how to correctly type objects when using useLocation?

Full code below:

Photo.tsx

import {FC} from 'react'
import {IPhotoComponent} from '../Main'
import { Link } from 'react-router-dom'

const Photo:FC<IPhotoComponent> = ({children, photo}):JSX.Element  => {


    return(
        <div className='photo'>
            <Link to = {`/photo/${photo.date}`} state = {photo}>
                <img src = {photo.url} />
            </Link>
        </div>
    )
}

export default Photo

PhotoDetails.tsx

import React, {FC, useState, useEffect} from 'react'
import { useParams, Params, useLocation } from 'react-router-dom'


const PhotoDetails:FC= ():JSX.Element => {

    interface IPhoto {
        copyright:string,
        date:string,
        explanation:string,
        hdurl:string,
        media_type:string,
        service_version:string,
        title:string,
        url:string
    }
    

    type PhotoParams = {
        id:string
    }

    const {id} = useParams<PhotoParams>()
    
    const {state } = useLocation<IPhoto>()
    console.log(state.url)

    return(
        <div>
            this is photo details
        </div>
    )
}

export default PhotoDetails

Upvotes: 0

Views: 888

Answers (1)

nart
nart

Reputation: 1848

According to react router docs useLocation

declare function useLocation(): Location;

interface Location extends Path {
  state: unknown;
  key: Key;
}

You can use interface Location import from the packages

import { useLocation, Location } from 'react-router-dom'
const { state } =  useLocation<Location>() 

Upvotes: 1

Related Questions