在卸载组件后保持状态

时间:2018-02-19 21:17:54

标签: reactjs react-router

我有一个Auth组件,负责 login & 注册。我只是收到道具(isSignup)并显示相应的表格字段。我也使用react-router

<BrowserRouter>
    <Route
        path="/signup" exact
        render={() => <Auth isSignup />} />
    <Route
        path="/login" exact
        render={() => <Auth />} />
</BrowserRouter>

Auth组件中,我有一个保存表单字段值的状态。

我希望在Auth卸载后保持状态,即当react-router不再呈现时,我可以在用户在{{1}之间切换时保留值}和/signup

如果没有全局状态管理(例如Redux),有没有办法做到这一点?

2 个答案:

答案 0 :(得分:0)

您可以创建一个包装器,用于存储组件上方的状态:

class AuthWrapper extends React.Component {
    constructor(props) {
        super(props);
        this.state = {};
    }

    render() {
        return ([
            <Route
                key="signup"
                path="/signup" exact
            >
                <Auth
                    state={this.state}
                    setState={(state) => this.setState(state)}
                    isSignup
                />
            </Route>,
            <Route
                key="login"
                path="/login" exact
            >
                <Auth
                    state={this.state}
                    setState={(state) => this.setState(state)}
                />
            </Route>
        ]);
    }
}

然后可以使用此组件,它将状态存储在这些路径上。

<BrowserRouter>
    <AuthWrapper />
</BrowserRouter>

您只需要在参数中使用state和setState,而不是在Auth组件中使用。

答案 1 :(得分:0)

如果您不想将Redux用于此目的,但您仍想在整个应用中分享此特定状态,那么有几种方法可以解决这个问题。如果你想留下&#34; Reacty&#34;,那么你真的有两个选择:

  1. 将状态作为道具传递
  2. 使用提供商
  3. 如果您只想要一些有效但不一定是React方式的东西,那么您有更多选择(例如设置window.isLoggedIn并随意切换它......我不推荐)

    对于这个答案,我们将专注于&#34; Reacty&#34;选项。

    将状态传递为道具

    这是React的默认方法。在组件树的根部某处跟踪您的isLoggedIn变量,然后通过道具将其传递给其他组件。

    class App extends Component {
      state = { isLoggedIn: false }
      logIn = () => this.setState({ isLoggedIn: true })
      logOut = () => this.setState({ isLoggedIn: false })
    
      render() {
        return (
          <BrowserRouter>
            <Route
              path="/signup" 
              exact
              render={() => (
                <Auth 
                  isSignup
                  isLoggedIn={this.state.isLoggedIn}
                  logIn={this.logIn}
                  logOut{this.logOut} 
                />
              )} 
            />
            <Route
              path="/login" 
              exact
              render={() => (
                <Auth 
                  isLoggedIn={this.state.isLoggedIn}
                  logIn={this.logIn}
                  logOut{this.logOut} 
                />
              )} 
            />
          </BrowserRouter>
        )
      }
    }
    

    这很有效,但需要将isLoggedInlogInlogOut传递给几乎所有组件。

    使用提供商

    Provider是一个React组件,它通过context将数据传递给其所有后代。

    class AuthProvider extends Component {
      state = { isLoggedIn: false }
      logIn = () => this.setState({ isLoggedIn: true })
      logOut = () => this.setState({ isLoggedIn: false })
    
      getChildContext() {
        return {
          isLoggedIn: this.state.isLoggedIn,
          logIn: this.logIn,
          logOut: this.logOut
        }
      }
    
      static childContextTypes = {
        isLoggedIn: PropTypes.bool,
        logIn: PropTypes.func,
        logOut: PropTypes.func
      }
    
      render() {
        return (
          <>
            {this.props.children}
          </>
        )
      }
    }
    

    然后,通过将整个内容包装在AuthProvider中来初始化您的应用:

    <AuthProvider>
      <BrowserRouter>
        // routes...
      </BrowserRouter>
    </AuthProvider>
    

    在您应用的任何组件中,您都可以通过isLoggedIn访问logInlogOutthis.context

    您可以在this excellent article from Robin Wieruch中详细了解Provider模式及其工作原理。

    注释:

    1. 使用更高阶组件接收context作为道具的组件很常见,但为了简洁,我将其排除在答案之外。 Robin's article进一步深入探讨。
    2. 您可能会将Provider模式识别为react-redux和其他状态管理库使用的模式。它在这一点上相当普遍。