[英]class component doesn't re-render when react router route changes
I have a question related to react-router and class components in React this is the first time I use class components in an app and I kind of get confused with lifecycle methods我有一个与 React 中的 react-router 和 class 组件有关的问题,这是我第一次在应用程序中使用 class 组件,我有点对生命周期方法感到困惑
my issue is I have a component where I display products in this component I switch categories of products where I do filter when switching as the API doesn't provide each category with its product so now I switch using react-router and I do change the route to "/category/:nameOfCategory"
when I click on the link of tech products in the address bar it changes but the component doesn't re-render as the props are not updating or refreshing this is where I do the request我的问题是我有一个组件,我在该组件中显示产品我切换了我在切换时进行过滤的产品类别,因为 API 没有为每个类别提供其产品,所以现在我使用 react-router 进行切换,我确实将路线更改为
"/category/:nameOfCategory"
当我点击地址栏中的科技产品链接时,它会改变,但组件不会重新渲染,因为道具没有更新或刷新这是我提出请求的地方
componentDidMount() {
request("http://localhost:4000/", getItems).then((ItemsData) => {
if (this.props.match.params.name === "all") {
this.setState({ products: ItemsData.category.products });
} else {
const filtered = ItemsData.category.products.filter((products) => {
let filteredProducts;
if (products.category === this.props.match.params.name) {
filteredProducts = products;
}
return filteredProducts;
});
this.setState({ products: filtered });
}
});
}
render() {
const { match, location } = this.props;
console.log(this.props);
return (
<div>
<h1 className="category-heading">{match.params.name}</h1>
<div className="category-items">
{this.state.products.map((product) => {
return <ItemCard key={location.key} productData={product} />;
})}
</div>
</div>
);
}
}
This is the route in App.js这是 App.js 中的路由
<Router>
<Navbar
/>
<Switch>
<Route
exact
path="/"
>
<Redirect to="/category/all" />
</Route>
<Route path="/category/:name" component={CategoryPage}/>
</Switch>
</Router>
The component correctly handles checking the routes params when the component mounts, but not when it rerenders when the params change.组件在安装组件时正确处理检查路由参数,但在参数更改时重新渲染时不会。
Implement the componentDidUpdate
lifecycle method to make the same request.实现
componentDidUpdate
生命周期方法以发出相同的请求。 To make the code more DRY you'll want to factor the request logic into a utility function.为了使代码更干燥,您需要将请求逻辑分解到实用程序 function 中。
getData = () => {
const { match: { params } } = this.props;
request("http://localhost:4000/", getItems)
.then((ItemsData) => {
if (params.name === "all") {
this.setState({ products: ItemsData.category.products });
} else {
const filtered = ItemsData.category.products.filter((products) => {
let filteredProducts;
if (products.category === params.name) {
filteredProducts = products;
}
return filteredProducts;
});
this.setState({ products: filtered });
}
});
};
componentDidMount() {
this.getData();
}
componentDidUpdate(prevProps) {
if (prevProps.match.params.name !== this.props.match.params.name) {
this.getData();
}
}
Note: There is an issue with react@18
's StrictMode
component and earlier versions of react-router-dom@5
.注意:
react@18
的StrictMode
组件和早期版本的react-router-dom@5
存在问题。 If this effects you then you should update to at least react-router-dom@5.3.3
.如果这影响到你,那么你应该至少更新到
react-router-dom@5.3.3
。 See this answer for more details.有关更多详细信息,请参阅此答案。
It is considered a bit of an anti-pattern to store derived state in React state.在 React state 中存储派生的 state 被认为是一种反模式。 The derived state here is the filtered result of applying that
name
parameter against the fetched data.此处派生的 state 是将
name
参数应用于获取的数据的过滤结果。 Instead of fetching all the data any time the filtering parameters change, you could fetch once when the component mounts and handle filtering inline when rendering.您可以在组件安装时获取一次并在渲染时处理内联过滤,而不是在过滤参数更改时获取所有数据。
getData = () => {
const { match: { params } } = this.props;
request("http://localhost:4000/", getItems)
.then((data) => {
this.setState({ products: data.category.products });
});
};
componentDidMount() {
this.getData();
}
render() {
const { match: { params } } = this.props;
return (
<div>
<h1 className="category-heading">{match.params.name}</h1>
<div className="category-items">
{this.state.products
.filter(product => {
if (params.name !== 'all') {
return product.category === params.name;
}
return true;
})
.map((product) => (
<ItemCard key={product.id} productData={product} />
))}
</div>
</div>
);
}
As a code improvement you can simplify the routing code a little bit.作为代码改进,您可以稍微简化路由代码。 Within the
Switch
component route path order and specificity matters.在
Switch
组件内,路由路径顺序和特异性很重要。 The Switch
component renders the first matching Route
or Redirect
component. Switch
组件呈现第一个匹配的Route
或Redirect
组件。 You'll generally want to order the routes in inverse order of path specificity, ie more specific paths before less specific paths.您通常希望以路径特异性的相反顺序对路线进行排序,即更具体的路径在不太具体的路径之前。 This eliminates the need to specify the
exact
prop.这消除了指定
exact
道具的需要。
The Redirect
component also takes a from
prop which is path you want to redirect from. Redirect
组件还接受一个from
道具,它是您要重定向的路径。
<Router>
<Navbar />
<Switch>
<Route path="/category/:name" component={CategoryPage} />
<Redirect from="/" to="/category/all" />
</Switch>
</Router>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.