javascript - React no vuelve a cargar los datos del componente en el cambio de parámetro de ruta o cambio de consulta
reactjs react-router (4)
Tengo un componente de "inicio" con enlaces, y cuando hace clic en un enlace, el componente del producto se carga con el producto. También tengo otro componente que siempre está visible, que muestra enlaces a los "productos visitados recientemente".
Estos enlaces no funcionan cuando se encuentra en la página de un producto. La url se actualiza cuando hago clic en el enlace y se produce un render, pero el componente del producto no se actualiza con el nuevo producto.
Ver este ejemplo: Ejemplo de códigos y cajas
Aquí están las rutas en 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>;
Los enlaces en ProductHistory se ven así:
<Link to={`/products/${product.product_id}`}> {product.name}</Link>
Por lo tanto, coinciden con la
Route path="/products/:product"
.
Cuando estoy en la página de un producto e intento seguir un enlace de ProductHistory, la URL se actualiza y se produce un render, pero los datos del componente no cambian. En el ejemplo de Codesandbox, puede descomentar la alerta en la función de representación de componentes del Producto para ver que se muestra cuando sigue el enlace, pero no sucede nada.
No sé cuál es el problema ... ¿Puede explicar el problema y encontrar una solución? ¡Eso seria genial!
Aunque todas las formas mencionadas funcionarán, no veo un punto para usar
getDerivedStateFromProps
.
Según los documentos de React, "si desea volver a calcular algunos datos solo cuando cambia un accesorio, utilice en su lugar un asistente de memorización".
Aquí, en cambio, sugeriría simplemente usar
componentDidUpdate
junto con cambiar el
Component
a
PureComponenet
.
Con referencia a los documentos React,
PureComponenet
s solo
PureComponenet
si al menos un estado o valor de prop cambia.
El cambio se determina haciendo una comparación superficial de las teclas de estado y de apoyo.
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
};
};
Tenga en cuenta que lo anterior solo funciona si cambia el Componente a PureComponent y, obviamente, necesita importarlo desde React.
Como el componente del Producto ya está cargado, no se volverá a cargar. Debe manejar la nueva identificación del producto en el siguiente método de componente
componentWillReceiveProps(nextProps) {
if(nextProps.match.params.name.product == oldProductId){
return;
}else {
//fetchnewProduct and set state to reload
}
Con la última versión de react (16.3.0 en adelante)
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
}
}
Junto con
componentDidMount
, también debe implementar el
componentWillReceiveProps
o usar
getDerivedStateFromProps
(desde la versión 16.0.0 en adelante) en la página de
Products
, ya que el mismo componente se
re-rendered
con
params
actualizados y
not re-mounted
cuando cambia los parámetros de ruta, esto es porque los parámetros se pasan como accesorios al componente y al cambiar los accesorios, los componentes React se vuelven a procesar y no se vuelven a montar.
EDITAR:
desde la v16.3.0 use
getDerivedStateFromProps
para establecer / actualizar el estado en función de los accesorios (no es necesario especificarlo en dos métodos de ciclo de vida diferentes)
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;
}
Anterior v16.3.0, usarías 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
})
}
}
Si no mantiene el estado en su componente, puede usar
componentDidUpdate
sin la necesidad de
getDerivedStateFromProps
:
componentDidUpdate(prevProps) {
const { match: { params: { value } } } = this.props
if (prevProps.match.params.value !== value){
doSomething(this.props.match.params.value)
}
}