首页 > 解决方案 > 在组件中使用渲染道具时,有哪些常见的陷阱可以避免无限重新渲染?

问题描述

假设我们正在使用 react-router-dom 在 react 中实现受保护的路由,我们必须牢记一些事情,例如在渲染私有路由时,组件确实会进入无限的重新渲染循环。

这条路线给我一个错误,最大调用堆栈超出反应防止无限重新渲染。这个组件有什么问题?PrivateRoute.jsx

const PrivateRoute = ({
  component: Component,
  isAuthenticated,
  token,
  ...rest
}) => {
  const employee = decoder(token);
  return (
    <Route
      {...rest}
      render={props =>
        isAuthenticated && employee.user.emp_role === "admin" ? (
          <Component {...props} />
        ) : (
          <Redirect to="/login" />
        )
      }
    />
  );
};

PrivateRoute.propTypes = {
  isAuthenticated: PropTypes.bool
};

const mapStateToProps = state => ({
  isAuthenticated: state.authReducer.isAuthenticated,
  token: state.authReducer.token
});

export default connect(mapStateToProps, { loadUser })(PrivateRoute);

我正在使用从 redux 状态映射到道具,选择必要的部分,例如 isAuthenticated 和令牌,令牌用于检查可能是管理员或员工的角色,将它们放入三元运算符等。这个组件的问题在哪里?

编辑 1:App.js

//imports here
if (localStorage.token) {
  setAuthToken(localStorage.token);
}

function App() {
  useEffect(() => {
    store.dispatch(loadUser());
  }, []);
  return (
    <Provider store={store}>
      <Router>
        <Alert />
        <Switch>
          <Layout>
            <Switch>
              <Route exact path="/" component={Landing} />
              <Route exact path="/login" component={Login} />
              <AdminRoutes exact path="/admin" component={Admin} />
              <AdminRoutes exact path="/employees" component={Employees} />
              <AdminRoutes exact path="/profile" component={Profile} />
              <AdminRoutes exact path="/chemists" component={Chemists} />
              <AdminRoutes
                exact
                path="/distributors"
                component={Distributors}
              />
              <AdminRoutes exact path="/doctors" component={Doctors} />
              <AdminRoutes exact path="/products" component={Products} />
            </Switch>
          </Layout>
        </Switch>
        <Switch>
          <PrivateRoute
            exact
            path="/representative"
            component={Representative}
          />
        </Switch>
      </Router>
    </Provider>
  );
}

export default App;

登录.jsx

const Login = ({ login, isAuthenticated, token }) => {
  const [formData, handleFormData] = useState({
    emp_phone: "",
    emp_password: ""
  });

  const { emp_password, emp_phone } = formData;

  const onSubmit = async e => {
    e.preventDefault();
    login(emp_phone, emp_password);
  };

  const handleLogin = e => {
    handleFormData({ ...formData, [e.target.name]: e.target.value });
  };

  // if (isAuthenticated) {
  //   const employee = decoder(token);
  //   if (employee.user.emp_role === "admin") {
  //     return <Redirect to="/admin" />;
  //   } else return <Redirect to="/representative" />;
  // }

  return (
    <Fragment>
      <div className="w-full max-w-sm shadow-md rounded p-5 m-3 align-middle h-auto">
        <form onSubmit={e => onSubmit(e)}>
          <div className="field self-center">
            <label className="label" htmlFor="phone">
              Phone Number
            </label>
            <div className="control">
              <input
                type="text"
                pattern="[0-9]*"
                id="phone"
                placeholder="Enter phone number"
                name="emp_phone"
                required
                value={emp_phone}
                onChange={e => handleLogin(e)}
                className="input"
              />
            </div>
          </div>
          <div className="field">
            <label className="label" htmlFor="password">
              Password
            </label>
            <div className="control">
              <input
                type="password"
                placeholder="Enter password"
                name="emp_password"
                id="password"
                value={emp_password}
                required
                onChange={e => handleLogin(e)}
                className="input"
              />
            </div>
          </div>
          <button type="submit" className="button is-primary">
            Login
          </button>
        </form>
      </div>
    </Fragment>
  );
};

Login.propTypes = {
  login: PropTypes.func.isRequired,
  isAuthenticated: PropTypes.bool
};

const mapStateToProps = state => ({
  isAuthenticated: state.authReducer.isAuthenticated,
  token: state.authReducer.token
});

export default connect(mapStateToProps, { login, loadUser })(Login);

标签: javascriptreactjs

解决方案


我认为问题可能是由于使用的逻辑。这也发生在我几周前。

isAuthenticated && employee.user.emp_role === "admin" ? (
      <Component {...props} />
    ) : (
      <Redirect to="/login" />
    )

在上面的代码中,当为 null 或 false(从本地存储加载期间)时,isAuthenticated 的值可以为 null 多次,这会多次触发 Redirect 组件。

你能试试下面的逻辑吗

!isAuthenticated && employee.user.emp_role !== "admin" ? (
      <Redirect to="/login" />
    ) : (
      <Component {...props} />
    )

推荐阅读