React Router: this is undefined
У меня есть небольшой проект из трех страниц, которые прекрасно работают, но проблема в следующем: я захотел на 3 странице добавить кнопку, которая будет переадресовывать на первую. Собственно проблемный компонент:
import React, {Component} from 'react';
import Car from './Car/Car';
export default class Cars extends Component {
state = {
cars: [
{name: 'Ford', year: 2018},
{name: 'Audi', year: 2016},
{name: 'Mazda', year: 2010}
]
}
goToHomePage = () => {
this.props.history.push({
pathname: '/'
})
}
render() {
return (
<div style={{
width: 400,
margin: 'auto',
paddingTop: '20px'
}}>
<button onClick={this.goToHomePage}>Click</button>
<hr />
{this.state.cars.map((car, index) => {
return (
<Car
key={index}
name={car.name}
year={car.year}
/>
)
})}
</div>
)
}
}
Вот моя кнопка, которая по клику вызывает функцию goToHomePage:
<button onClick={this.goToHomePage}>Click</button>
И непосредственно функция:
goToHomePage = () => {
this.props.history.push({
pathname: '/'
})
}
Мне выдает такую ошибку:
TypeError: undefined is not an object (evaluating 'this.props.history.push')
Понимаю, что props почему-то не видно, но хотелось бы понять, почему конкретно.
Ответы (3 шт):
В классовом компоненте нужно добавить конструктор (и начальное состояние тоже в конструкторе нужно объявить):
constructor(props) {
super(props);
this.state = {
cars: [
{ name: "Ford", year: 2018 },
{ name: "Audi", year: 2016 },
{ name: "Mazda", year: 2010 }
]
};
}
Дополнение про React Router 6
В 6 версии React Router больше нет withRouter, который пробрасывал в пропсы объект history. Поэтому для классовых компонентов придется добавить свой hoc:
function withNavigation(Component) {
return (props) => <Component {...props} navigate={useNavigate()} />;
}
Компонент нужно обернуть в withNavigation и после этого в компоненте можно использовать функцию их пропсов navigate:
goToHomePage = () => {
this.props.navigate("/");
};
В функциональных компонентах просто используется хук useNavigate:
const navigate = useNavigate();
const goToHomePage = () => {
navigate("/");
};
Пример на codesandbox - https://codesandbox.io/s/infallible-browser-u78e1?file=/src/Page3.jsx
Решение проблемы: переписать функцию goToHomePage:
goToHomePage = () => {
window.location.assign('/');
}
Насколько я понимаю, вариант из моего вопроса использовался раньше, когда роуты передавались через атрибут component таким образом:
<Routes>
<Route path="/about" exact component ={Cars} />
</Routes>
Теперь же, насколько я понимаю, такой синтаксис устарел, а используется синтаксис с атрибутом element, а в таком случае this работает иначе:
<Routes>
<Route path="/" exact element={<Cars />} />
</Routes>
Возможно, я допустил некие неточности в объяснении, но по крайней мере, это решает проблему
import React, { Component } from "react";
import { UNSAFE_NavigationContext } from "react-router-dom";
import Car from "./Car/Car";
export default class Cars extends Component {
static contextType = UNSAFE_NavigationContext;
state = {
cars: [
{ name: "Ford", year: 2018 },
{ name: "Audi", year: 2016 },
{ name: "Mazda", year: 2010 },
],
};
goToHomePage = () => {
this.context.navigator.push("/");
};
render() {
return (
<div
style={{
width: 400,
margin: "auto",
paddingTop: "20px",
}}
>
<button onClick={this.goToHomePage}>Click</button>
<hr />
{this.state.cars.map((car, index) => {
return <Car key={index} name={car.name} year={car.year} />;
})}
</div>
);
}
}