React 不会在路由参数更改或查询更改时重新加载组件数据
React doesn't reload component data on route param change or query change
我有一个带有 link 的 "home" 组件,当您单击 link 时,产品组件随产品一起加载。我还有另一个始终可见的组件,向 "recently visited products".
显示 links
这些 link 在产品页面上不起作用。当我单击 link 时 url 会更新,并且会出现渲染,但产品组件不会随新产品一起更新。
看这个例子:
Codesandbox example
index.js中的路线如下:
<BrowserRouter>
<div>
<Route
exact
path="/"
render={props => <Home products={this.state.products} />}
/>
<Route path="/products/:product" render={props => <Product {...props} />} />
<Route path="/" render={() => <ProductHistory />} />
<Link to="/">to Home</Link>
</div>
</BrowserRouter>;
ProductHistory 中的 link 如下所示:
<Link to={`/products/${product.product_id}`}> {product.name}</Link>
所以他们匹配 Route path="/products/:product"
.
当我在产品页面上并尝试关注 ProductHistory link 时,URL 会更新并进行渲染,但组件数据不会更改。在 Codesandbox 示例中,您可以取消注释 Product components render 函数中的警报,以查看它在您遵循 link 时呈现,但没有任何反应。
我不知道问题出在哪里...您能解释一下问题并找到解决方案吗?那太好了!
由于产品组件已经加载,因此不会重新加载。您必须在组件
的以下方法中处理新产品 ID
componentWillReceiveProps(nextProps) {
if(nextProps.match.params.name.product == oldProductId){
return;
}else {
//fetchnewProduct and set state to reload
}
使用最新版本的 react(16.3.0 以上)
static getDerivedStateFromProps(nextProps, prevState){
if(nextProps.productID !== prevState.productID){
return { productID: nextProps.productID};
}
else {
return null;
}
}
componentDidUpdate(prevProps, prevState) {
if(prevProps.productID !== this.state.productID){
//fetchnewProduct and set state to reload
}
}
与 componentDidMount
一起,您还需要在 Products
页面中实现 componentWillReceiveProps
或使用 getDerivedStateFromProps
(从 v16.3.0 开始),因为相同的组件是re-rendered
更新了 params
和 not re-mounted
当你更改路由参数时,这是因为参数作为 props 传递给组件并且在 props 更改时,React 组件重新渲染而不是重新渲染已安装。
编辑: 从 v16.3.0 使用 getDerivedStateFromProps
到 set/update 基于道具的状态(不需要在两种不同的生命周期方法中指定它)
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.match.params.product !== prevState.currentProductId){
const currentProductId = nextProps.match.params.product
const result = productlist.products.filter(obj => {
return obj.id === currentProductId;
})
return {
product: result[0],
currentId: currentProductId,
result
}
}
return null;
}
在 v16.3.0 之前,您将使用 componentWillReceiveProps
componentWillReceiveProps(nextProps) {
if (nextProps.match.params.product !== this.props.match.params.product) {
const currentProductId = nextProps.match.params.product
const result = productlist.products.filter(obj => {
return obj.id === currentProductId;
})
this.setState({
product: result[0],
currentId: currentProductId,
result
})
}
}
如果您不在组件中维护状态,则可以使用 componentDidUpdate
而无需 getDerivedStateFromProps
:
componentDidUpdate(prevProps) {
const { match: { params: { value } } } = this.props
if (prevProps.match.params.value !== value){
doSomething(this.props.match.params.value)
}
}
尽管所有 above-mentioned 方法都可以使用,但我看不到使用 getDerivedStateFromProps
的意义。
基于 React 文档,"if you want to re-compute some data only when a prop changes, use a memoization helper instead"。
在这里,相反,我建议简单地使用 componentDidUpdate
并将 Component
更改为 PureComponenet
。
参考 React 文档,PureComponenet
只有在至少一个状态或道具值发生变化时才会重新渲染。更改是通过对状态键和道具键进行浅层比较来确定的。
componentDidUpdate = (prevProps) => {
if(this.props.match.params.id !== prevProps.match.params.id ) {
// fetch the new product based and set it to the state of the component
};
};
请注意,以上仅在将 Component 更改为 PureComponent 时有效,显然,您需要从 React 导入它。
我有一个带有 link 的 "home" 组件,当您单击 link 时,产品组件随产品一起加载。我还有另一个始终可见的组件,向 "recently visited products".
显示 links这些 link 在产品页面上不起作用。当我单击 link 时 url 会更新,并且会出现渲染,但产品组件不会随新产品一起更新。
看这个例子: Codesandbox example
index.js中的路线如下:
<BrowserRouter>
<div>
<Route
exact
path="/"
render={props => <Home products={this.state.products} />}
/>
<Route path="/products/:product" render={props => <Product {...props} />} />
<Route path="/" render={() => <ProductHistory />} />
<Link to="/">to Home</Link>
</div>
</BrowserRouter>;
ProductHistory 中的 link 如下所示:
<Link to={`/products/${product.product_id}`}> {product.name}</Link>
所以他们匹配 Route path="/products/:product"
.
当我在产品页面上并尝试关注 ProductHistory link 时,URL 会更新并进行渲染,但组件数据不会更改。在 Codesandbox 示例中,您可以取消注释 Product components render 函数中的警报,以查看它在您遵循 link 时呈现,但没有任何反应。
我不知道问题出在哪里...您能解释一下问题并找到解决方案吗?那太好了!
由于产品组件已经加载,因此不会重新加载。您必须在组件
的以下方法中处理新产品 IDcomponentWillReceiveProps(nextProps) {
if(nextProps.match.params.name.product == oldProductId){
return;
}else {
//fetchnewProduct and set state to reload
}
使用最新版本的 react(16.3.0 以上)
static getDerivedStateFromProps(nextProps, prevState){
if(nextProps.productID !== prevState.productID){
return { productID: nextProps.productID};
}
else {
return null;
}
}
componentDidUpdate(prevProps, prevState) {
if(prevProps.productID !== this.state.productID){
//fetchnewProduct and set state to reload
}
}
与 componentDidMount
一起,您还需要在 Products
页面中实现 componentWillReceiveProps
或使用 getDerivedStateFromProps
(从 v16.3.0 开始),因为相同的组件是re-rendered
更新了 params
和 not re-mounted
当你更改路由参数时,这是因为参数作为 props 传递给组件并且在 props 更改时,React 组件重新渲染而不是重新渲染已安装。
编辑: 从 v16.3.0 使用 getDerivedStateFromProps
到 set/update 基于道具的状态(不需要在两种不同的生命周期方法中指定它)
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.match.params.product !== prevState.currentProductId){
const currentProductId = nextProps.match.params.product
const result = productlist.products.filter(obj => {
return obj.id === currentProductId;
})
return {
product: result[0],
currentId: currentProductId,
result
}
}
return null;
}
在 v16.3.0 之前,您将使用 componentWillReceiveProps
componentWillReceiveProps(nextProps) {
if (nextProps.match.params.product !== this.props.match.params.product) {
const currentProductId = nextProps.match.params.product
const result = productlist.products.filter(obj => {
return obj.id === currentProductId;
})
this.setState({
product: result[0],
currentId: currentProductId,
result
})
}
}
如果您不在组件中维护状态,则可以使用 componentDidUpdate
而无需 getDerivedStateFromProps
:
componentDidUpdate(prevProps) {
const { match: { params: { value } } } = this.props
if (prevProps.match.params.value !== value){
doSomething(this.props.match.params.value)
}
}
尽管所有 above-mentioned 方法都可以使用,但我看不到使用 getDerivedStateFromProps
的意义。
基于 React 文档,"if you want to re-compute some data only when a prop changes, use a memoization helper instead"。
在这里,相反,我建议简单地使用 componentDidUpdate
并将 Component
更改为 PureComponenet
。
参考 React 文档,PureComponenet
只有在至少一个状态或道具值发生变化时才会重新渲染。更改是通过对状态键和道具键进行浅层比较来确定的。
componentDidUpdate = (prevProps) => {
if(this.props.match.params.id !== prevProps.match.params.id ) {
// fetch the new product based and set it to the state of the component
};
};
请注意,以上仅在将 Component 更改为 PureComponent 时有效,显然,您需要从 React 导入它。