#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);