# React router: 使用 Prompt 在路由状态变化时进行交互


在使用 react router 时，我们可以使用 history.listen() 在路由变化时进行一些操作，比如 dispatch action 这样的操作，那如果是需要交互提醒是否要跳转的情况呢？

答案是* [Prompt](https://reacttraining.com/react-router/core/api/Prompt)*.

根据[官方文档](https://reacttraining.com/react-router/core/api/Prompt)，我们可以用下面的方式使用 *Prompt*：

```
<Prompt
  when={formIsHalfFilledOut}
  message="Are you sure you want to leave?"
/>
```

> [when: bool](https://reacttraining.com/core/api/Prompt/when-bool)
> Instead of conditionally rendering a `&lt;Prompt&gt;` behind a guard, you can always render it but pass `when={true}` or `when={false}` to prevent or allow navigation accordingly.

而 *message *可以接受* string | function*，那么我们就有了下面的用法:

```
<Prompt
  when={formIsHalfFilledOut}
  message={ saved ? true : 'Please save before leaving.' }
/>
```


在实际应用中，我们会面临多个页面都需要 Prompt 的情况，这是把它独立成一个组件是最方便的做法。

但在 *React 16+*中，多个组件嵌套时周期调用发生[一些调整](https://reactjs.org/blog/2017/09/26/react-v16.0.html#breaking-changes)，实际上我们在使用的过程中很可能会遇到[这个问题](https://github.com/ReactTraining/react-router/issues/5707)：
> “Warning: A history supports only one prompt at a time”

解决方案其实也很简单，在 *cDM *和 *cWU *时分别切换 *when *的状态就可以了

```jsx
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

```
