从通过 React Router 设置的路由访问 Redux Store

新手上路,请多包涵

我想利用 react-router 的 onEnter 处理程序来提示用户在进入受限路由时进行身份验证。

到目前为止,我的 routes.js 文件看起来像这样:

 import React from 'react';
import { Route, IndexRoute } from 'react-router';

export default (
    <Route   path="/"         component={App}>
      <IndexRoute             component={Landing} />
      <Route path="learn"     component={Learn} />
      <Route path="about"     component={About} />
      <Route path="downloads" component={Downloads} onEnter={requireAuth} />
    </Route>
)

理想情况下,我希望我的 requireAuth 函数是一个可以访问商店和当前状态的 redux 操作,其工作方式如下: store.dispatch(requireAuth())

不幸的是,我无权访问此文件中的商店。我不认为我可以真正使用 connect 在这种情况下访问我想要的相关操作。我也不能只从创建商店的文件中获取 import store ,因为当应用首次加载时这是未定义的。

原文由 robinnnnn 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 435
2 个回答

完成此操作的最简单方法是将您的商店传递给返回您的路线的函数(而不是直接返回您的路线)。通过这种方式,您可以访问 onEnter 中的商店和其他反应路由器方法。

所以对于你的路线:

 import React from 'react';
import { Route, IndexRoute } from 'react-router';

export const getRoutes = (store) => (
  const authRequired = (nextState, replaceState) => {
    // Now you can access the store object here.
    const state = store.getState();

    if (!state.user.isAuthenticated) {
      // Not authenticated, redirect to login.
      replaceState({ nextPathname: nextState.location.pathname }, '/login');
    }
  };

  return (
    <Route   path="/"         component={App}>
      <IndexRoute             component={Landing} />
      <Route path="learn"     component={Learn} />
      <Route path="about"     component={About} />
      <Route path="downloads" component={Downloads} onEnter={authRequired} />
    </Route>
  );
)

然后更新您的主要组件以调用 getRoutes 函数,传入商店:

 <Provider store={ store }>
  <Router history={ history }>
    { getRoutes(store) }
  </Router>
</Provider>

至于从 requireAuth 调度一个动作,你可以这样写你的函数:

 const authRequired = (nextState, replaceState, callback) => {
  store.dispatch(requireAuth())  // Assume this action returns a promise
    .then(() => {
      const state = store.getState();

      if (!state.user.isAuthenticated) {
        // Not authenticated, redirect to login.
        replaceState({ nextPathname: nextState.location.pathname }, '/login');
      }

      // All ok
      callback();
    });
};

希望这可以帮助。

原文由 Ashley ‘CptLemming’ Wilson 发布,翻译遵循 CC BY-SA 3.0 许可协议

如果你想要,你可以这样写 route.js :

 var requireAuth = (store, nextState, replace) => {
  console.log("store: ", store);
  //now you have access to the store in the onEnter hook!
}

export default (store) => {
  return (
      <Route path="/"           component={App}>
        <IndexRoute             component={Landing} />
        <Route path="learn"     component={Learn} />
        <Route path="about"     component={About} />
        <Route path="downloads" component={Downloads} onEnter={requireAuth.bind(this, store)} />
      </Route>
    );
);

我已经设置了一个示例,您可以在此 codepen 中使用它。

不确定触发操作以处理身份验证是否是个好主意。我个人更喜欢 以不同的方式 处理身份验证:

我没有使用 onEnter 挂钩,而是使用了包装函数。我希望我的博客的管理部分受到保护,因此我将 AdminContainer 组件包装在具有函数 requireAuthentication 的路由中,见下文。

 export default (store, history) => {
        return (
            <Router history={history}>
                <Route path="/" component={App}>
                    { /* Home (main) route */ }
                    <IndexRoute component={HomeContainer}/>
                    <Route path="post/:slug" component={PostPage}/>
                    { /* <Route path="*" component={NotFound} status={404} /> */ }
                </Route>

                <Route path="/admin" component={requireAuthentication(AdminContainer)}>
                    <IndexRoute component={PostList}/>
                    <Route path=":slug/edit" component={PostEditor}/>
                    <Route path="add" component={PostEditor}/>
                </Route>
                <Route path="/login" component={Login}/>
            </Router>
        );
    };

requireAuthentication 是一个函数

  • 如果用户通过身份验证,则呈现包装的组件,
  • 否则重定向到 Login

你可以在下面看到它:

 export default function requireAuthentication(Component) {
    class AuthenticatedComponent extends React.Component {

        componentWillMount () {
            this.checkAuth();
        }

        componentWillReceiveProps (nextProps) {
            this.checkAuth();
        }

        checkAuth () {
            if (!this.props.isAuthenticated) {
                let redirectAfterLogin = this.props.location.pathname;
                this.context.router.replace({pathname: '/login', state: {redirectAfterLogin: redirectAfterLogin}});
            }
        }

        render () {
            return (
                <div>
                    {this.props.isAuthenticated === true
                        ? <Component {...this.props}/>
                        : null
                    }
                </div>
            )

        }
    }

    const mapStateToProps = (state) => ({
        isAuthenticated: state.blog.get('isAuthenticated')
    });

    AuthenticatedComponent.contextTypes = {
        router: React.PropTypes.object.isRequired
    };

    return connect(mapStateToProps)(AuthenticatedComponent);
}

此外, requireAuthentication 将保护 /admin 下的所有路由。你可以在任何你喜欢的地方重复使用它。

原文由 Alex Chirițescu 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题