Skip to main content

Command Palette

Search for a command to run...

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

Updated
1 min read

在使用 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 &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+中,多个组件嵌套时周期调用发生一些调整,实际上我们在使用的过程中很可能会遇到这个问题

“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
164 views

More from this blog

Al's blog

21 posts