React路由器在每次更新时都会卸载和重装子组件。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React路由器在每次更新时都会卸载和重装子组件。相关的知识,希望对你有一定的参考价值。
我已经创建了一个组件,这是一个包装器周围的形式组件。
class RestaurantEdit extends React.Component {
constructor(props) {
super(props)
this.state = { waitingForRequest: false }
}
componentDidUpdate(prevProps) {
const { currentRequestState } = this.props
const { waitingForRequest } = this.state
if (
waitingForRequest &&
prevProps.currentRequestState === requestStates.PENDING &&
currentRequestState === requestStates.SUCCESS
) {
this.props.history.goBack()
this.setState({ waitingForRequest: false })
}
}
handleSubmit = (restaurantInfos, restaurantId) => {
const { editRestaurant } = this.props
const { password, ...dataWithoutPassword } = restaurantInfos
this.setState({ waitingForRequest: true })
if (password === '') {
editRestaurant(restaurantId, dataWithoutPassword)
} else {
editRestaurant(restaurantId, restaurantInfos)
}
}
handleCancel = () => {
this.props.history.goBack()
}
render() {
const { id, data = {} } = this.props
const { password, ...dataWithoutPassword } = data
return (
<RestaurantForm
id={id}
data={dataWithoutPassword}
onCancel={this.handleCancel}
onSubmit={this.handleSubmit}
isPasswordRequired={false}
/>
)
}
}
const mapStateToProps = state => ({
currentRequestState: restaurantSelectors.getRequestState(state)
})
const mapDispatchToProps = dispatch => ({
editRestaurant: (restaurantId, restaurantInfos) => {
dispatch(editRestaurantRequested(restaurantId, restaurantInfos))
}
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(RestaurantEdit)
这个组件被挂载在它的父级React router switch中。
<Switch>
<Route
path="/restaurants/new"
exact
component={props => (
<RestaurantCreate onSuccess={this.handleSuccess} {...props} />
)}
/>
<Route
path="/restaurants/edit"
component={props => {
const id = props.location.search.split('=')[1]
const data = currentCityRestaurants.find(resto => resto.id === id)
return <RestaurantEdit id={id} data={data} {...props} />
}}
>
</Route>
<Route
path="/restaurants"
exact
component={/* otherComponent */}
/>
</Switch>
我的大问题是,当我试图调度一个动作时(例如 editRestaurant
,这是给 RestaurantEdit
作为道具的mapDispatchToProps),商店正在更新,这将使组件卸载并重新装载。
这种卸载将防止 this.setState({ waitingForRequest: true })
在 componentDidUpdate
完成,以及 waitingForRequest
空穴来风
我注意到,如果我把组件作为一个直接的子代传给了 Route
卸载重装将不会发生。
<Route
path="/restaurants/edit"
exact
>
<RestaurantEdit …… />
</Route>
但我不能使用这个解决方案,因为我需要访问... location
和 history
提供 Route
组件。
所以,当我将组件作为 component
榰 Route
?
当你想要在路由中渲染一个元素时增加一些功能,你需要使用 render
键词 component
在你的例子中
<Route
path="/restaurants/edit"
component={props => {
const id = props.location.search.split('=')[1]
const data = currentCityRestaurants.find(resto => resto.id === id)
return <RestaurantEdit id={id} data={data} {...props} />
}}
>
将组件关键字改为render,并使用函数返回修改后的组件。
<Route
path="/restaurants/edit"
render={ props => {
const id = props.location.search.split('=')[1]
const data = currentCityRestaurants.find(resto => resto.id === id)
return (<RestaurantEdit id={id} data={data} {...props} />)
}}
>
这样就可以方便地进行内联渲染和包装,而不会出现上述不受欢迎的重装。
https:/reacttraining.comreact-routerwebapiRouterender-func。
当你在渲染周期中使用匿名函数时,就会发生这种情况。React并不知道你的匿名函数的输出与上次渲染的结果是一样的,这就是为什么组件会卸载和重装。
说到这里,你不需要使用渲染道具函数来获取Route道具的访问权。它们已经作为道具传递给你的组件了。
<Route
path="/restaurants/edit"
component={RestaurantEdit}
/>
const RestaurantEdit = (props) => {
console.log(props.location, props.history)
return ...
}
以上是关于React路由器在每次更新时都会卸载和重装子组件。的主要内容,如果未能解决你的问题,请参考以下文章
React Hook - 仅在组件卸载时使用效果,而不是在依赖项更新时使用
每次更改页面时都会调用 React useEffect (with []) (React Router)