React hooks - useState() 中的状态在路由更改时不会重置
React hooks - state in useState() is not reset when route is changed
const Create = () => {
console.log('rerender !!')
const [parcelType, setParcelType] = useState('paper')
console.log('parcelType =', parcelType)
return (
<Container onClick={() => setParcelType('plastic')}>
<BookingList />
<Card title="Business">
<p>Header</p>
</Card>
</Container>
)
}
export default Create
我想在创建组件中单击 Container 时将 parcelType 状态更改为 'plastic'。我想在路线更改时将 parcelType 状态重置为 'paper'(创建组件重新渲染)。但是当组件重新渲染状态没有设置为 paper
更多详细信息:当 BookingList 组件中的路由更改时,CreateComponent 会重新渲染
const BookingList = props => {
const { id } = props.match.params
const containerStyle = useTranslateSpring('-100px', '0')
const itemList = items.map((item, idx) => {
const itemStyle = useTranslateSpring('-100px', '0', '0', 200 + 200 * idx)
const url = `/booking/${item.id}/create`
return (
<ItemContainer
onClick={() => props.history.push(url)}
style={itemStyle}
key={item.id}
isactive={id === item.id}
>
{item.id}
</ItemContainer>
)
})
return <Container style={containerStyle}>{itemList}</Container>
}
export default withRouter(BookingList)
创建组件通过routeTemplate在路由中渲染
const Routes = () => (
<Router basename={process.env.REACT_APP_BASE_URL}>
<>
<RouteTemplate
exact
path="/booking/:id/create"
component={Booking.create}
title="Booking"
/>
</>
</Router>
)
而RouteTemplate是由PageTemplate组件包裹的render组件
const RouteTemplate = props => {
const {
component: Component,
title,
query,
isAuthenticated,
isLanding,
...rest
} = props
return (
<Route
{...rest}
render={matchProps =>
isAuthenticated ? (
<PageTemplate title={title} isLanding={isLanding}>
<Component {...matchProps} query={query} />
</PageTemplate>
) : (
<Redirect
to={{
pathname: '/',
state: { from: props.location },
}}
/>
)
}
/>
)
}
所以我假设您想在路由更改后重置组件的状态。
只要您使用函数式组件 + 挂钩或具有显式 this.state
的基于 class 的组件,都应该发生这种情况。这就是 React 在底层的工作方式。
- 您已经
<Create>
在页面呈现
- 路线改变后
<Route>
尝试渲染<Create>
元素
- React 看到已经存在
<Create>
元素 并尝试更新它而不是重新创建(通常更新比重新创建更有效)。这就是状态未重置的原因 - 因为它不应该为更新重置。
有不同的处理方法。
如果这种情况发生在 react-router 的 <Route>
之外,我建议 use key
prop 重置状态。但是对于 <Route>
这意味着用更冗长的 <Route path="..." render={({match}) => <Create match={match} key={match.params.id} />}
替换更多的 clear/straightforward <Route path="..." component={Create} />
因此,让我们应用 useEffect
钩子来在 props.match.params.id
更改后重置状态:
const Create = ({ match: {params: {id} } }) => {
useEffect(() => {
setParcelType('paper');
}, [id]);
那应该等于class-based
state = {
typeOfWhatEver: 'paper'
};
componentDidUpdate(prevProps) {
if(prevProps.match.params.id !== this.props.match.params.id) {
this.setState({
typeOfWhatEver: 'paper'
});
}
}
const Create = () => {
console.log('rerender !!')
const [parcelType, setParcelType] = useState('paper')
console.log('parcelType =', parcelType)
return (
<Container onClick={() => setParcelType('plastic')}>
<BookingList />
<Card title="Business">
<p>Header</p>
</Card>
</Container>
)
}
export default Create
我想在创建组件中单击 Container 时将 parcelType 状态更改为 'plastic'。我想在路线更改时将 parcelType 状态重置为 'paper'(创建组件重新渲染)。但是当组件重新渲染状态没有设置为 paper
更多详细信息:当 BookingList 组件中的路由更改时,CreateComponent 会重新渲染
const BookingList = props => {
const { id } = props.match.params
const containerStyle = useTranslateSpring('-100px', '0')
const itemList = items.map((item, idx) => {
const itemStyle = useTranslateSpring('-100px', '0', '0', 200 + 200 * idx)
const url = `/booking/${item.id}/create`
return (
<ItemContainer
onClick={() => props.history.push(url)}
style={itemStyle}
key={item.id}
isactive={id === item.id}
>
{item.id}
</ItemContainer>
)
})
return <Container style={containerStyle}>{itemList}</Container>
}
export default withRouter(BookingList)
创建组件通过routeTemplate在路由中渲染
const Routes = () => (
<Router basename={process.env.REACT_APP_BASE_URL}>
<>
<RouteTemplate
exact
path="/booking/:id/create"
component={Booking.create}
title="Booking"
/>
</>
</Router>
)
而RouteTemplate是由PageTemplate组件包裹的render组件
const RouteTemplate = props => {
const {
component: Component,
title,
query,
isAuthenticated,
isLanding,
...rest
} = props
return (
<Route
{...rest}
render={matchProps =>
isAuthenticated ? (
<PageTemplate title={title} isLanding={isLanding}>
<Component {...matchProps} query={query} />
</PageTemplate>
) : (
<Redirect
to={{
pathname: '/',
state: { from: props.location },
}}
/>
)
}
/>
)
}
所以我假设您想在路由更改后重置组件的状态。
只要您使用函数式组件 + 挂钩或具有显式 this.state
的基于 class 的组件,都应该发生这种情况。这就是 React 在底层的工作方式。
- 您已经
<Create>
在页面呈现 - 路线改变后
<Route>
尝试渲染<Create>
元素 - React 看到已经存在
<Create>
元素 并尝试更新它而不是重新创建(通常更新比重新创建更有效)。这就是状态未重置的原因 - 因为它不应该为更新重置。
有不同的处理方法。
如果这种情况发生在 react-router 的 <Route>
之外,我建议 use key
prop 重置状态。但是对于 <Route>
这意味着用更冗长的 <Route path="..." render={({match}) => <Create match={match} key={match.params.id} />}
<Route path="..." component={Create} />
因此,让我们应用 useEffect
钩子来在 props.match.params.id
更改后重置状态:
const Create = ({ match: {params: {id} } }) => {
useEffect(() => {
setParcelType('paper');
}, [id]);
那应该等于class-based
state = {
typeOfWhatEver: 'paper'
};
componentDidUpdate(prevProps) {
if(prevProps.match.params.id !== this.props.match.params.id) {
this.setState({
typeOfWhatEver: 'paper'
});
}
}