javascript - 如何使用 react-router 将顶级组件状态向下传递给路由?

标签 javascript react-router reactjs

我已经使用通过 Firebase 进行身份验证的 react-router 设置了一个 React 应用。

我有这个工作,但我现在希望能够从主 App 组件管理登录用户 (auth) 的状态,并将其传递给子组件而不是必须查询每个组件中的身份验证状态。

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Link, browserHistory } from 'react-router';
import { createHistory } from 'history';

/*
  Firebase
*/
import Auth from './modules/Auth';
import Helpers from './modules/Helpers';

// Auth.unauth();
/*
  Import app modules
*/
import LogIn from './modules/LogIn';
import LogOut from './modules/LogOut';
import NotFound from './modules/NotFound';
import Register from './modules/Register';
import Dashboard from './modules/Dashboard';
import ResetPassword from './modules/ResetPassword';
import ChangePassword from './modules/ChangePassword';
import MyAccount from './modules/MyAccount';


const App = React.createClass({

  getInitialState: function() {
    return {
      loggedIn: Auth.getAuth(),
      userType: null
    }
  },

  setUserLevel: function(authData) {
    if(authData){
      Auth.child('users/'+authData.uid+'/user_level').once('value',
        (snapshot) => {
          this.setState({ userType: Helpers.getUserType(snapshot.val()) })
        },
        (error) => {
          this.setState({
            userType: Helpers.getUserType(0),
            error: error
          });
        }
      );
    }
  },

  updateAuth: function(loggedIn) {
    // console.log('Updating Auth');

    this.setUserLevel(loggedIn);

    this.setState({
      loggedIn: loggedIn
    })
  },

  componentWillMount: function() {
    Auth.onAuth(this.updateAuth);
  },

  render: function() {

    var regButton = (this.state.loggedIn) ? null : (<Link className="Navigation__link" to="register">Register</Link>);
    var accountButton = (this.state.loggedIn) ? (<Link className="Navigation__link" to="account">My Account</Link>) : null;

    return (
    <div>
      <nav className="Navigation">
        {this.state.loggedIn ? (
            <Link className="Navigation__link" to="/logout">Log out</Link>
          ) : (
            <Link className="Navigation__link" to="/login">Sign in</Link>
        )}
        {regButton}
        {accountButton}
        <Link className="Navigation__link" to="dashboard">Dashboard</Link>
      </nav>
      <div>
      {this.props.children}
      </div>
    </div>);
  }
})


function requireAuth(nextState, replaceState) {
  if (!Auth.getAuth())
    replaceState({ nextPathname: nextState.location.pathname }, '/login')
}

function notWhenLoggedIn(nextState, replaceState) {
  if (Auth.getAuth())
    replaceState({ nextPathname: nextState.location.pathname }, '/dashboard')
}

var routes = (
  <Router history={createHistory()}>
    <Route path="/" component={App}>
      <Route path="/login" component={LogIn} onEnter={notWhenLoggedIn} />
      <Route path="/logout" component={LogOut} onEnter={requireAuth} />
      <Route path="/register" component={Register} onEnter={notWhenLoggedIn} />
      <Route path="/resetpassword" component={ResetPassword} onEnter={notWhenLoggedIn} />
      <Route path="/change-password" component={ChangePassword} onEnter={requireAuth} />
      <Route path="/dashboard" component={Dashboard} onEnter={requireAuth} />
      <Route path="/account" component={MyAccount} onEnter={requireAuth} />
      <Route path="*" component={NotFound} />
    </Route>
  </Router>
)

ReactDOM.render(routes, document.querySelector('#main'));

我现在陷入困境,因为我找不到一种方法将 App 组件的 loggedIn state 作为子组件的属性向下传递。

这甚至可以用 react-router 实现吗?

最佳答案

我知道的最好方法是使用 the React.Children utility .这是一个快速的 Codepen,可以看到这个概念的实际应用。 http://codepen.io/anon/pen/RrKbjZ

因此,您的示例中 App 组件的 render() 函数中的代码将如下所示。

render: function() {

  var regButton = (this.state.loggedIn) ? null : (<Link className="Navigation__link" to="register">Register</Link>);
  var accountButton = (this.state.loggedIn) ? (<Link className="Navigation__link" to="account">My Account</Link>) : null;
  var childrenWithProps = React.Children.map(this.props.children, (Child, i) => {
    return React.cloneElement(Child, {
      loggedIn: this.state.loggedIn
    });
  });

  return (
    <div>
      <nav className="Navigation">
        {
          this.state.loggedIn ? 
          (<Link className="Navigation__link" to="/logout">Log out</Link>) :
          (<Link className="Navigation__link" to="/login">Sign in</Link>)  
        }
        {regButton}
        {accountButton}
        <Link className="Navigation__link" to="dashboard">Dashboard</Link>
      </nav>
      <div>
        {childrenWithProps}
      </div>
    </div>
  );
}

关于javascript - 如何使用 react-router 将顶级组件状态向下传递给路由?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34547884/

相关文章:

javascript - 命令处理程序中的 Discord.js 音乐机器人

javascript - 仅选择已更改的下拉菜单

reactjs - 使用浅渲染测试 react-router

reactjs - 在选择器中访问 react 路由器状态

javascript - 如何根据不同的键将 JSON 数组重新格式化为另一种格式 "grouping"

javascript - Push 函数改变了 React 中的 props

javascript - 如何通过字符串名称创建类的实例?我也尝试将 `window` 用于这些目的。

javascript - 导入错误 : 'useNavigate' is not exported from 'react-router-dom'

reactjs - 如何安装react-toastr

javascript - 从对象键构建字符串