web-dev-qa-db-fra.com

React Router - Erreurs TypeScript sur withRouter après la mise à jour de la version

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'.

35
29er

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);
82
Pavel

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);
23
jakobdo

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)
);
5
Max

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);
    }
}
3
Daniel Krom

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) => {
1
oliyoung

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
    );
1
Jackkobec

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:

  • Les parties importantes sont les interfaces, RouteComponentProps, type Props, React typage des composants et l'exportation par défaut avec Router (...). MapStateToProps et mapDispatchToProps ne sont que des exemples.
  • IAppState définit les saisies du magasin redux de mon application. Si vous ne l'avez pas.
  • J'utilise un magasin redux immuable ici (c'est pourquoi "state.getIn ...").
0
Raunhofer