история реакции.push не работает, как и история использования

#reactjs #react-router-dom #spfx

Вопрос:

Я хочу перенаправить на другую страницу при отправке формы.

Я прочитал и видел несколько статей, в которых советуется использовать:

 this.props.history.push("/")
 

А также предложение использовать:

 import { useHistory  } from 'react-router-dom';
//Followed by
let history = useHistory();
history.push("/");
 

Однако ни то, ни другое не работает для меня,:

 this.props.history.push("/")
 

Выдает следующую ошибку:

 Uncaught (in promise) TypeError: _this.props.history.push is not a function
 

И использование:

 import { useHistory  } from 'react-router-dom';
//Followed by
let history = useHistory();
history.push("/");
 

выдает следующую ошибку:

 sp-webpart-workbench-assembly_en-us_3b6fc7db2fe02279bf3499609f870638.js:69 Uncaught (in promise) Error: Minified React error #321; visit https://reactjs.org/docs/error-decoder.html?invariant=321
 

Для справки, вот как выглядит мой компонент, никаких повторяющихся вызовов:

     import * as React from 'react';
import { HttpClient, AadHttpClient, SPHttpClient, SPHttpClientConfiguration, HttpClientResponse, ODataVersion, ISPHttpClientConfiguration } from '@microsoft/sp-http';
import styles from './MyChildComponent.module.scss';
import { MyChildComponentProps } from './MyChildComponentProps';
import { Form, Formik, Field } from 'formik';
import {
  FormikTextField,
  FormikDropdown,
} from 'formik-office-ui-fabric-react';
import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react';
import { FormValuesValidation } from '../../utility/FormValuesValidation';
import { useHistory  } from 'react-router-dom';

export default class MyChildComponent extends React.Component<MyChildComponentProps, {}> {
  private error: Error = null;
 
  public constructor(props: MyChildComponentProps){
   super(props);
   this.state = {
   };
 }

  public componentDidMount() {
          
  }

  public render(): React.ReactElement<MyChildComponentProps> {

    let formValues = new FormValuesValidation();
    formValues.assignment = this.props.memberID;
    formValues.fullname = this.props.name;
      
    return (
      <div className={ styles.MyChildComponent}>
        <div>
          <Formik
            initialValues={formValues}
            onSubmit={(values, actions) => {
              try{
                this.props.service.postMyForm(this.props.memberID, values)
                .then((result) => {
                 switch (result) {
                   case 200:
                      this.props.history.push("/");
                   case 500 : case 404: case 401:
                      this.props.history.push("/errorPage");
                   default:
                     break;
                 }
                },
                  (error: any) => {
                    console.log("Something really bad happened", error);
                  }
                );
              } catch (e) {
                console.log("an error occured", e);
                this.error = e;
              }
            }}
            render={({ values, touched, errors, ...props }) => (
              
              <div>
                <form onSubmit={props.handleSubmit}>

                  <Field
                    name="fullname"
                    label="Employee Name"
                    component={FormikTextField}
                    disabled
                  />

                  <Field
                    name="memberID"
                    label="Employee No"
                    component={FormikTextField}
                    disabled
                  />                  

                  <div style={{ marginTop: '1em' }}>
                    <PrimaryButton
                      type="submit"
                      disabled={!props.dirty || !props.isValid}
                    >
                      Submit
                    </PrimaryButton>
                    amp;nbsp;
                    <DefaultButton
                      type="button"
                      onClick={() => props.resetForm()}
                      disabled={!props.dirty}
                    >
                      Reset
                    </DefaultButton>
                  </div>
                </form>
              </div>
            )}
          />
        </div>
      </div>
    );
  }
}
 

Компонент, в котором я пытаюсь это сделать, является дочерним компонентом и передает историю в качестве реквизита компоненту.

Любая помощь будет признательна!

Комментарии:

1. Работает ли this.props.history.push({ путь: «/» });?

2. Вам нужно добавить еще немного контекста о том, как вы их используете. Не видя этого, все, что я могу сказать: крючки (например useHistory ) можно использовать только в корпусе функциональных компонентов . this.props.history доступно только для вас, если вы завернули компонент withRouter или определили Route его определенным образом.

3. @rrd к сожалению, нет, та же ошибка: this.props.history не является функцией.

4. @BrianThompson, я обновил свой вопрос.

5. Я не вижу withRouter , чтобы он использовался, поэтому , если этот компонент не передается history либо другим вашим компонентом, либо через параметры маршрута напрямую Route , то именно поэтому это не работает.

Ответ №1:

Вы должны использовать withRouter, чтобы иметь возможность использовать объект истории, как указано в документе react-router:

Вы можете получить доступ к свойствам объекта истории и ближайшему совпадению с помощью компонента более высокого порядка withRouter. withRouter будет передавать обновленные данные о совпадении, местоположении и истории завернутому компоненту всякий раз, когда он будет отображаться.

Так что, как доктор, вы должны сделать что-то вроде этого:

 class YourComponent extends React.Component {

  render() {
    const history = this.props.history;

    return <button onClick={() => {history.push("/")}}></button>;
  }
}

const YourComponentWithRouter = withRouter(YourComponent);
 

Комментарии:

1. Спасибо за этот Саджад, он указал мне в правильном направлении, чтобы решить мою проблему! Хотя сначала мне пришлось преобразовать мой функциональный компонент в компонент класса, а также импортировать RouteComponentProps

Ответ №2:

Поэтому я решил эту проблему, преобразовав мой функциональный компонент в компонент класса, а затем импортировав:

 import { RouteComponentProps } from 'react-router';
 

Поскольку я получал следующую ошибку:

 Argument of type 'typeof MyChildComponent ' is not assignable to parameter of type 'ComponentType<RouteComponentProps<any, StaticContext, unknown>>'.
 

Ошибка была вызвана типами, поскольку я использую Typescript, ниже показано, как выглядит мой преобразованный/завершенный код, мне пришлось расширить свои реквизиты для использования RouteComponentProps:

 import * as React from 'react';
import { HttpClient, AadHttpClient, SPHttpClient, SPHttpClientConfiguration, HttpClientResponse, ODataVersion, ISPHttpClientConfiguration } from '@microsoft/sp-http';
import styles from './MyChildComponent.module.scss';
import { Form, Formik, Field } from 'formik';
import {
  FormikTextField,
  FormikDropdown,
} from 'formik-office-ui-fabric-react';
import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react';
import { FormValuesValidation } from '../../utility/FormValuesValidation';
import { useHistory, withRouter, Redirect  } from 'react-router-dom';
import { RouteComponentProps } from 'react-router';
import { MyServices} from "../../../services/myservices/services";


class MyChildComponent extends React.Component<MyChildComponentProps> {
  private error: Error = null;
 
  public constructor(props: MyChildComponentProps){
   super(props);
 }

    public componentDidMount() {    

  }

    public render(): React.ReactElement<MyChildComponentProps> {
        let formValues = new FormValuesValidation();
    formValues.memberID= this.props.memberID;
    formValues.fullname = this.props.name;

    return (
<div className={ styles.MyChildComponent}>
        <div>
          <Formik
            initialValues={formValues}
            onSubmit={(values, actions) => {
              try{
                this.props.service.postForm(this.props.memberID, values)
                .then((result) => {
                 switch (result) {
                   case 200:
                     this.props.history.push("/");
                     break;
                   case 500 : case 404: case 401:
                      this.props.history.push("/errorPage");
                      break;
                   default:
                     break;
                 }
                },
                  (error: any) => {
                    console.log("Something really bad happened", error);
                  }
                );
              } catch (e) {
                console.log("an error occured", e);
                this.error = e;
              }
            }}
            render={({ values, touched, errors, ...props }) => (
              
              <div>
                <form onSubmit={props.handleSubmit}>

                  <Field
                    name="fullname"
                    label="Employee Name"
                    component={FormikTextField}
                    disabled
                  />

                  <Field
                    name="memberID"
                    label="Employee No"
                    component={FormikTextField}
                    disabled
                  />                      

                  <div style={{ marginTop: '1em' }}>
                    <PrimaryButton
                      type="submit"
                      disabled={!props.dirty || !props.isValid}
                    >
                      Submit
                    </PrimaryButton>
                    amp;nbsp;
                    <DefaultButton
                      type="button"
                      onClick={() => props.resetForm()}
                      disabled={!props.dirty}
                    >
                      Reset
                    </DefaultButton>
                  </div>
                </form>
              </div>
            )}
          />
        </div>
      </div>
        );
    }
}

export interface MyChildComponentProps extends RouteComponentProps {
  description: string;
  service: MyServices;
  memberID: string;
  name: string;
}

export default withRouter(MyChildComponent);