Je viens d'essayer de mettre à jour mon React app to
react-router - 4.0.19 à 4.0.20
réagir- 16.0.30 à 16.0.34
TypeScript- version "2.7.0-insiders.20180108"
Dans mon application, où que j'utilise 'withRouter', j'obtiens maintenant des erreurs cryptographiques TypeScript. J'ai même remplacé tous les accessoires d'interface par "any" juste pour essayer de le faire fonctionner.
import * as React from 'react';
import { Switch, Route, withRouter} from 'react-router-dom';
import { Login } from './Login';
import { connect } from 'react-redux';
import { RootAction, RootState } from './_redux';
class MainForm extends React.Component<any> {
constructor(props: any) {
super(props);
}
render() {
return (
<Switch>
<Route exact={true} path="/" component={Login}/>
<Route path="/accounts" component={AccountsView}/>
</Switch>
);
}
}
const mapStateToProps = (state: RootState) => ({
state
});
export const Main = withRouter(connect(mapStateToProps)(MainForm);
erreur TS2345: argument de type "ComponentClass> & {WrappedComponent: ComponentType; } 'n'est pas attribuable au paramètre de type' ComponentType> '. Tapez 'ComponentClass> & {WrappedComponent: ComponentType; } 'n'est pas assignable au type' StatelessComponent> '. Tapez 'ComponentClass> & {WrappedComponent: ComponentType; } 'ne fournit aucune correspondance pour la signature' (accessoires: RouteComponentProps & {children ?: ReactNode;}, context ?: any): ReactElement | nul'.
Si je convertis la dernière ligne en ceci:
export const Main = connect(mapStateToProps)(MainForm);
Je n'ai pas d'erreurs. sérieusement frustré ici. Merci
MODIFIER , je suis passé à
export const Main = connect(mapStateToProps)(withRouter(MainForm));
comme suggéré par Mayank Shukla. mais maintenant obtenez l'erreur:
erreur TS2345: l'argument de type "ComponentClass>" n'est pas attribuable au paramètre de type "ComponentType <{état: RootState; } & DispatchProp> '. Le type 'ComponentClass>' n'est pas assignable au type 'StatelessComponent <{state: RootState; } & DispatchProp> '. Le type 'ComponentClass>' ne fournit aucune correspondance pour la signature '(props: {state: RootState;} & DispatchProp & {children ?: ReactNode;}, context ?: any): ReactElement | nul'.
Je viens de passer à TypeScript 2.6 et j'ai le même problème.
J'ai réussi à le résoudre en utilisant RouteComponentProps
.
Pour l'URL http://localhost:8080/your-component/abc
et itinéraire
<Route component={YourComponent} path="/your-component/:param1?" />
Le composant doit ressembler à ceci:
import * as React from 'react'
import { withRouter } from 'react-router-dom';
import {RouteComponentProps} from "react-router";
// Type whatever you expect in 'this.props.match.params.*'
type PathParamsType = {
param1: string,
}
// Your component own properties
type PropsType = RouteComponentProps<PathParamsType> & {
someString: string,
}
class YourComponent extends React.Component<PropsType> {
render() {
console.log(this.props); // Prints all props including routing-related
console.log(this.props.match.params.param1); // Prints 'abc'
console.log(typeof this.props.match.params.param1 === 'string'); // prints 'true'
return <div>...</div>;
}
}
export default withRouter(YourComponent);
Je dois le résoudre comme ceci:
import * as React from 'react';
import { RouteComponentProps, withRouter } from 'react-router-dom';
interface IProps extends RouteComponentProps<any> {
title: string;
}
class MyComp extends React.Component<IProps> {
public render(){
return (
<h1>{this.props.title}</h1>
)
}
}
export default withRouter<IProps>(MyComp);
Voici comment je strucutre habituellement mes composants typés React:
// These props are provided when creating the component
interface OwnProps {
// ...
}
// These props are provided via connecting the component to the store
interface StateProps {
// ...
}
// These props are provided by the router
interface PathProps {
// ...
}
class Component extends React.Component<OwnProps & StateProps & RouteComponentProps<PathProps>> {
// ...
}
const mapStateToProps = (state: State, props: OwnProps): StateProps => ({
// ...
});
export default withRouter(
connect(mapStateToProps)(Component)
);
Une autre solution, en utilisant des décorateurs
import { withRouter, RouteComponentProps } from "react-router";
// inform we match url /:id
interface IMatchParams {
id: string;
}
// Note we use Partial<RouteComponentProps> to make all RouteComponentProps as optional for high order component
interface IComponentProps extends Partial<RouteComponentProps<IMatchParams>> {
myPersonalProp: string;
}
@withRouter
export default class MyClass extends React.Component<IComponentProps>{
public componentDidMount(){
console.log(this.props.match.params.id);
}
}
Voici une approche de réaction fonctionnelle que j'utilise
import { RouteComponentProps } from "react-router";
interface Props extends RouteComponentProps {
thing: Thing | false;
onAction?: () => void;
}
export default withRouter(({ thing, onAction, history }: Props) => {
La variante de syntaxe de travail pour l'application de script de type est:
import * as React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
interface ComponentProps {
// Your properties here
}
interface ComponentState {
// Your properties here
}
interface MapStateToPropsTypes {
// Your properties here
}
interface MapDispatchToPropsTypes {
// Your properties here
}
class MyComponentName extends React.Component<ComponentProps, ComponentState> {
constructor(props: ComponentProps) {
super(props);
}
}
export default withRouter(
connect<MapStateToPropsTypes, MapDispatchToPropsTypes>(
mapStateToProps,
mapDispatchToProps
)(MyComponentName) as any
);
Je rencontrais des problèmes très similaires/identiques avec TypeScript 3.6 et je n'ai pas pu trouver de solution en ligne, je vais donc partager ma propre solution ici. J'espère que cela aide quelqu'un qui travaille avec une application plus complexe.
import React, { memo } from 'react';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { ThunkDispatch } from 'redux-thunk';
import { connect } from 'react-redux';
import { AnyAction } from 'redux';
interface IStateProps {
name: string;
sessionLanguage: string;
}
interface IDispatchProps {
handleLogout: () => void;
}
type Props = IStateProps & IDispatchProps & RouteComponentProps<any>;
const MyCoolComponent = ({
sessionLanguage,
handleLogout,
history,
}: Props) => {
return null;
};
const mapStateToProps = (state: IAppState): IStateProps => ({
name: state.getIn(['session', 'name']),
sessionLanguage: state.getIn(['session', 'language']),
});
const mapDispatchToProps = (
dispatch: ThunkDispatch<{}, {}, AnyAction>
): IDispatchProps => ({
handleLogout: async () => {
await dispatch(logout());
},
});
export default withRouter(
connect<IStateProps, IDispatchProps, {}, IAppState>(
mapStateToProps,
mapDispatchToProps
)(memo(NavigationLayout))
);
Quelques notes: