Jim Greer
Jim Greer

Reputation: 461

React TypeScript: Correct type for useLocation() from react-router-dom

I'm struggling to find the right type for this situation. This is a simplified version of redirecting after login. The following produces a compiler error:

Property 'from' does not exist on type '{} | { from: { pathname: string; }; }'.

Adding as any to the use of location.state fixes the compiler error but it's ugly and the linter complains.

import React from "react";
import { useLocation } from "react-router-dom";

const AuthLayer: React.FC = (props) => {
  const location = useLocation();

  const { from } = location.state || { from: { pathname: "/" } };

  return <p></p>;
};

export default AuthLayer;

Upvotes: 35

Views: 59331

Answers (8)

ibtissem rezig
ibtissem rezig

Reputation: 1

If you are using React Router v6, the useLocation hook does not accept a generic parameter directly as it did in some custom or modified type definitions or potentially older versions. Instead, you should define the state type separately and use it where needed. Here’s how you can do this correctly

import { useLocation } from 'react-router-dom';
    
interface LocationState {
   from: string;
}
    
const MyComponent: React.FC = () => {
  const location = useLocation();
  const state = location.state as LocationState; // Type assertion here
    
  return (
  <div>
    {state && <p>From: {state.from}</p>}
  </div>
 );
};
    
export default MyComponent;

Upvotes: 0

Salwa A. Soliman
Salwa A. Soliman

Reputation: 746

In react-router-dom version 6, it can be done like that

const locationState = useLocation().state as {id: string}; 

const id = locationState.id;

Upvotes: 2

PitterPark
PitterPark

Reputation: 1

If you send only one thing, What about using useParams instead of useLocation?

function routeDetails(id: string) {
    history.push({
      pathname: `/details/${pathname}`,
    });
  }
const { id } = useParams<{ id: string }>();

You can use useParams simply. It has key 'id' that is from history pathname.

Upvotes: -4

JulienRioux
JulienRioux

Reputation: 3092

This will be a little type-safe since it will return undefined if from is not in the object instead of throwing an error.

import React from "react";
import { useLocation } from "react-router-dom";

type LocationState = {
  from: {
    path: string;
  }
}

const AuthLayer: React.FC = (props) => {
  const location = useLocation();
  
  // πŸ‘‡πŸ‘‡πŸ‘‡
  const from = (location.state as LocationState)?.from;

  return <p></p>;
};

export default AuthLayer;

Upvotes: 3

LeulAria
LeulAria

Reputation: 615

export interface LocationParams {
  pathname: string;
  state: your_state_data_type;
  search: string;
  hash: string;
  key: string;
}

//...
const location = useLocation<LocationParams>()

or create a generic that u can use any where

// types.ts
export interface LocationParams<Data> {
  pathname: string;
  state: Data;
  search: string;
  hash: string;
  key: string;
}


// App.tsx
import { LocationParams } from './types.ts'

// ...
const location = useLocation<LocationParams<your_data_here>>()

Upvotes: 2

Prakhar Varshney
Prakhar Varshney

Reputation: 271

Type Assertion would work here.

import React from "react";
import { useLocation } from "react-router-dom";

type LocationState = {
  from: {
    path: string;
  }
}

const AuthLayer: React.FC = (props) => {
  const location = useLocation();

  const { from } = location.state as LocationState;

  return <p></p>;
};

export default AuthLayer;

Also, remember to define the type, as per your requirements. For example, you might be using navigate(state.from).

For this Define the type as -

type LocationState = {
  from : string;
}

Upvotes: 27

omdjin
omdjin

Reputation: 389

You can use Location from 'history'.

import React from "react";
import { Location } from "history";
import { useLocation } from "react-router-dom";


const AuthLayer: React.FC = (props) => {
  const location = useLocation<Location>();

  const { from } = location.state || { from: { pathname: "/" } };

  return <p></p>;
};

export default AuthLayer;

Upvotes: 13

falinsky
falinsky

Reputation: 7428

You can create a particular type or interface to describe your location state and then use it when calling a useLocation hook:

import React from "react";
import { useLocation } from "react-router-dom";

interface LocationState {
  from: {
    pathname: string;
  };
}

const AuthLayer: React.FC = (props) => {
  const location = useLocation<LocationState>();

  const { from } = location.state || { from: { pathname: "/" } };

  return <p></p>;
};

export default AuthLayer;

Upvotes: 36

Related Questions