React router: 使用 Prompt 在路由状态变化时进行交互
在使用 react router 时,我们可以使用 history.listen() 在路由变化时进行一些操作,比如 dispatch action 这样的操作,那如果是需要交互提醒是否要跳转的情况呢?
答案是 Prompt.
根据官方文档,我们可以用下面的方式使用 Prompt:
<Prompt
when={formIsHalfFilledOut}
message="Are you sure you want to leave?"
/>
when: bool Instead of conditionally rendering a
<Prompt>behind a guard, you can always render it but passwhen={true}orwhen={false}to prevent or allow navigation accordingly.
而 message 可以接受 string | function,那么我们就有了下面的用法:
<Prompt
when={formIsHalfFilledOut}
message={ saved ? true : 'Please save before leaving.' }
/>
在实际应用中,我们会面临多个页面都需要 Prompt 的情况,这是把它独立成一个组件是最方便的做法。
但在 React 16+中,多个组件嵌套时周期调用发生一些调整,实际上我们在使用的过程中很可能会遇到这个问题:
“Warning: A history supports only one prompt at a time”
解决方案其实也很简单,在 cDM 和 cWU 时分别切换 when 的状态就可以了
import React from 'react'
import { Prompt } from 'react-router-dom'
// why we need *when* here?
// Prompt in React 16 "Warning: A history supports only one prompt at a time" [1]
// [1] https://github.com/ReactTraining/react-router/issues/5707
const initState = {
when: false,
showPrompt: false,
}
class PromptWrapper extends React.Component {
state = initState
componentDidMount() {
this.setState({
when: true,
})
}
componentWillReceiveProps({ showPrompt }) {
window.onbeforeunload = showPrompt
? () => true
: null
this.setState({
title,
showPrompt,
})
}
componentWillUnmount() {
this.setState({
...initState,
})
window.onbeforeunload = null
}
render() {
return (
<React.Fragment>
<Prompt
when={this.state.when}
message={() => this.state.showPrompt
? `Sure to leave?`
: true
} />
{this.props.children}
</React.Fragment>
)
}
}
export default PromptWrapper


