如何在 react redux 中添加受保护的路由

Rul*_*ure 14 javascript ecmascript-6 reactjs redux react-redux

我创建了一个登录组件,其中包含所有逻辑内容。

登录减速器是:

const openState = {
  loggedIn: null,
  user: null
}

export default (state = openState, action) => {
  switch (action.type) {
    case LOGIN:
      return { ...state, loggedIn: true, user: action.payload }
    case LOGOUT:
      return { ...state, loggedIn: false, user: null }
    default:
      return openState
  }
}
Run Code Online (Sandbox Code Playgroud)

那个行动 :

export const logIn = (user) => {
  return {
    type: LOGIN,
    payload: user
  }
}

export const logOut = () => {
  return {
    type: LOGOUT
  }
}
Run Code Online (Sandbox Code Playgroud)

一切正常,但我不确定如何将actionloggedInuserprops 从 action传递到路由组件以保护所有路由:

const MainRoutes = props => {
  const { loggedIn } = props;

  console.log(props.loggedIn)

return (
  <Router history={history}>
    <Baseline />
    <Menu/>
    <Container maxWidth="md">
      <Switch>
        <Route exact path="/Login" component={Login} />
        <Route exact path="/Carousel" component={Carousel} />
        <Route exact path="/Stepper" component={Stepper} />
        <Route component={NotFound} />
      </Switch>
    </Container>
  </Router>
);
}

const mapStateToProps = (state) => {
return { loggedIn: state.loggedIn };
};

export default connect(mapStateToProps)(MainRoutes);
Run Code Online (Sandbox Code Playgroud)

如果我将控制台.logloggedIn道具我得到未定义:| 基于loggedIn我可以在路由组件中创建一个逻辑。

str*_*tss 9

您可以简单地定义一个ProtectedRoute将连接到 redux 状态的自定义组件。在您的情况下,它应该映射state.auth.loggedInstate.auth.user道具并执行 aRedirect如果这些值是假的:

import React from "react";
import { Route, Redirect } from "react-router-dom";
import PropTypes from "prop-types";


const ProtectedRoute = (props) => {
  const { redirectPath, component, user, loggedIn, ...routeProps} = props;
  const Component = component;
  const isAccessible = Boolean(user) && loggedIn;

  return (
    <Route
      {...routeProps}
      render={props => {
        if (isAccessible) return <Component {...props} />;
        return <Redirect to={{ pathname: redirectPath || "/Login" }} />;
      }}
    />
  );
};

ProtectedRoute.propTypes = {
  path: PropTypes.string.isRequired,
  redirectPath: PropTypes.string,
  component: PropTypes.oneOfType([
    PropTypes.shape({ render: PropTypes.func.isRequired }),
    PropTypes.func
  ]),
};

const mapStateToProps = (state) => {
  return { 
    loggedIn: state.auth.loggedIn, 
    user: state.auth.user 
  };
};

export default connect(mapStateToProps)(ProtectedRoute);
Run Code Online (Sandbox Code Playgroud)

有了这个,你MainRoutes就不再需要connect了:

const MainRoutes = props => {
  return (
    <Router history={history}>
      ...
      <Container maxWidth="md">
        <Switch>
          <Route exact path="/Login" component={Login} />
          <ProtectedRoute exact path="/Carousel" component={Carousel} />
          <ProtectedRoute exact path="/Stepper" component={Stepper} />
          <Route component={NotFound} />
        </Switch>
      </Container>
    </Router>
  );
}

export default MainRoutes;
Run Code Online (Sandbox Code Playgroud)

更新:

如果你想auth在页面刷新后保持状态,你需要对你的 redux store 进行一些额外的设置。主要思想是订阅每个操作并将状态的新副本放入localStorageorcookiesinitialState在您的应用程序启动之前从选定的存储中持久化。下面是一个例子:

function getFromStorage(key) {
  try {
    return JSON.parse(window.localStorage.getItem(key)) || {};
  } catch (err) {
    return {};
  }
}

const initialState = getFromStorage("APP_STATE");

const store = createStore(
  rootReducer,
  initialState, // should go after root reducer
  ...
);

store.subscribe(() => {
  window.localStorage.setItem("APP_STATE", JSON.stringify(store.getState()));
});
Run Code Online (Sandbox Code Playgroud)

这是工作沙箱(由SuleymanSah引导)


Sul*_*Sah 4

正如其他人已经描述的那样,您最好创建一条受保护的路由来完成您想要的任务。如果用户尚未登录,您只需将用户重定向到登录路由即可。

这是我的实现:(codesandbox

import React from "react";
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";

const ProtectedRoute = ({
  path,
  component: Component,
  render,
  loggedIn,
  ...rest
}) => {
  return (
    <Route
      path={path}
      {...rest}
      render={(props) => {
        if (loggedIn) {
          return Component ? <Component {...props} /> : render(props);
        }
        return (
          <Redirect
            to={{
              pathname: "/login",
              state: { from: props.location }
            }}
          />
        );
      }}
    />
  );
};

const mapStateToProps = (state) => {
  const { loggedIn } = state.auth;
  return {
    loggedIn
  };
};

export default connect(mapStateToProps)(ProtectedRoute);
Run Code Online (Sandbox Code Playgroud)