reactjs - React Typescript - Hvordan tilføjer man typer til location.state, når det sendes i en Route
Jeg får en fejl, når jeg sender react-router props til en komponent i en Route, fordi jeg har en specifik state, som jeg sender til denne komponent, men fejlen vises i min Route.
Her er rutekoden:
<Route
exact
path='/flipltimeline'
render={props => <FliplTimeline {...props} />
I en anden komponent kalder jeg dette nedenfor
props.history.push(`/flipltimeline`, {
Approval: singleFliplApprovals,
InvestigationID,
Unit: unit,
Cost: cost
});
Her er koden til komponenten. Jeg fik endelig Typescript til at kompilere dette, men jeg var nødt til at flette LocationState & TimelineState for at få det til at fungere. Men nu kaster Typescript ovenstående skærmbillede, når jeg sender props til min FliplTimeline-komponent. Er der nogen, der har en idé om, hvordan man løser dette?
history.tsx
import { createBrowserHistory } from 'history';
let baseNameProd = '';
if (process.env.NODE_ENV !== 'production') {
console.log('Looks like we are in development mode!');
baseNameProd = '';
} else {
baseNameProd = '/flipl';
}
const customHistory = createBrowserHistory({
basename: baseNameProd
});
export default customHistory;
FliplTimeline.tsx
import * as React from 'react';
import { History, LocationState } from 'history';
interface FliplTimelineLocationState {
Approval: any;
InvestigationID: number;
Unit: string;
Cost: number;
}
interface TimelineState{
state: FliplTimelineLocationState;
}
interface Props {
history: History;
location: LocationState & TimelineState;
}
function FliplTimeline(props: Props) {
return (
<ModuleTemplate title='Status Timeline' subtitle=''>
<FliplTimelineJumbotron className='bg-primary-darker shadow-4 line-height-serif-4'>
<div className='grid-row'>
<div className='grid-col-4'>
<span
className='font-mono-2xl text-white'
style={{
verticalAlign: 'middle'
}}
>
FLIPL{' '}
</span>
<span
className='font-mono-xl text-gold'
style={{
verticalAlign: 'middle'
}}
>
{props.location.state.InvestigationID}
</span>
Opdatering: Tilføjede min history.tsx-fil, hvor jeg oprettede min egen historik til React-Router. Tilføjede også i import-sætningerne.
Opdatering: Forsøgte at ændre min FliplTimeline-komponent til at have dette interface
import { RouteComponentProps } from 'react-router-dom'
function FliplTimeline(props: RouteComponentProps ) {
Jeg får 2 fejl. Den første er denne, og en anden siger, at formen på props er forkert. Ideer?
Opdatering: Jeg var endelig i stand til at få den korrekte props-deklaration til min komponent.
import { RouteComponentProps } from 'react-router-dom';
interface FliplTimelineLocationState {
Approval: any;
InvestigationID: number;
Unit: string;
Cost: number;
}
function FliplTimeline(
props: RouteComponentProps<{}, any, FliplTimelineLocationState | any>
)
Svar #1
Jeg var i stand til at få det til at fungere.
import { RouteComponentProps } from 'react-router-dom';
interface FliplTimelineLocationState {
Approval: any;
InvestigationID: number;
Unit: string;
Cost: number;
}
function FliplTimeline(
props: RouteComponentProps<{}, any, FliplTimelineLocationState | any>
)
Svar #2
Brug RouteComponentProps og giv den de passende typer til dens generiske. Denne artikel dækker en hel del: Hvordan man bruger React Router i Typescript.
At bruge React Router med TypeScript kræver næsten, at man udfylder de generiske typer, som React Router har. Ellers er der ikke nok kontekst til at bestemme typerne af alting. Sammenlign med mit eksempel nedenfor. Jeg bruger useHistory og udfylder den med den type, som jeg ønsker skal være tilgængelig. Dette ville sandsynligvis være din FliplTimelineLocationState, sådan at state-egenskaben af history kunne bestemmes til at være af typen FliplTimelineLocationState.
import React, {MouseEventHandler} from "react";
import {Route, RouteComponentProps, StaticContext, useHistory} from "react-router";
import {BrowserRouter, Link} from "react-router-dom";
interface IMyScreenRouteParams {
foo: string;
}
// You don't have to extend, you could just use StaticContext
interface IMyStaticContext extends StaticContext {
bar: string;
}
interface IHistory {
fizz: string;
}
const Nav = () => {
const history = useHistory<IHistory>();
const clickHanlder: MouseEventHandler = () => {
history.push("/my-screen", {
fizz: "you said fizz"
});
};
return (
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/my-screen">My Screen</Link></li>
<li><button onClick={clickHanlder}>My Screen with state</button></li>
<li><Link to="/my-screen?q=hello">My Screen with query</Link></li>
<li><Link to="/my-screen/bob">My Screen using match</Link></li>
</ul>
<div>
<button onClick={() => history.goBack()}>Back</button>
<button onClick={() => history.push("/")}>Home</button>
<button onClick={() => history.goForward()}>Forward</button>
</div>
</nav>
);
};
const MyScreen = ({
location,
match,
history,
staticContext
}: RouteComponentProps<IMyScreenRouteParams, IMyStaticContext, IHistory>) => (
<div>
<section>
<h2>Location</h2>
<p><code>location</code> has <code>IHistory</code> props.</p>
<pre><code>{JSON.stringify(location, null, 4)}</code></pre>
</section>
<section>
<h2>Match</h2>
<p><code>match</code> has <code>IMyScreenRouteParams</code> props.</p>
<pre><code>{JSON.stringify(match, null, 4)}</code></pre>
</section>
<section>
<h2>History</h2>
<p><code>history</code> has <code>IHistory</code> props.</p>
<pre><code>{JSON.stringify(history, null, 4)}</code></pre>
</section>
<section>
<h2>Static Context</h2>
<p><code>staticContext</code> has <code>IMyStaticContext</code> props or whatever static context your router has.</p>
<p>This is for a <a href="https://reacttraining.com/react-router/web/api/StaticRouter/context-object"><code><StaticRouter/></code></a>.</p>
<pre><code>{JSON.stringify(staticContext, null, 4)}</code></pre>
</section>
</div>
);
const Router = () => (
<BrowserRouter>
<div
style={{
display: "flex",
flexDirection: "row"
}}
>
<Nav />
<main>
<Route exact path="/" component={() => (<div>Click something in the <code><nav/></code></div>)} />
<Route exact path="/my-screen" component={MyScreen} />
<Route exact path="/my-screen/:id" component={MyScreen} />
</main>
</div>
</BrowserRouter>
);
export default Router;

