手写一个简单的react-router6 Part2

书接上文,我们还有很多功能没有实现,比如说我们经常会用到路由守卫控制登录、注销等,在react-router6中如何使用呢?

我们看一下代码。

js 复制代码
export default function App() {
  return (
    <div className="app">
      <AuthProvider>
        <Router>
          <Routes>
            <Route path="/" element={<Layout />}>
              <Route path="/" element={<Home />} />
              <Route path="product" element={<Product />}>
                <Route path=":id" element={<ProductDetail />} />
              </Route>
              <Route
                path="user"
                element={
                  <RequiredAuth>
                    <User />
                  </RequiredAuth>
                }
              />
              <Route path="login" element={<Login />} />
              <Route path="*" element={<NoMatch />} />
            </Route>
          </Routes>
        </Router>
      </AuthProvider>
    </div>
  );
}

function Layout() {
  return (
    <div className="border">
      <Link to="/">首页</Link>
      <Link to="/product">商品</Link>
      <Link to="/user">用户中心</Link>
      <Link to="/login">登录</Link>
      <Outlet />
    </div>
  );
}

function Home() {
  return (
    <div>
      <h1>Home</h1>
    </div>
  );
}

function Product() {
  return (
    <div>
      <h1>Product</h1>

      <Link to="/product/123">商品详情</Link>

      <Outlet />
    </div>
  );
}

function ProductDetail() {
  let navigate = useNavigate();
  const params = useParams();
  return (
    <div>
      <h1>ProductDetail</h1>
      <p>{params.id}</p>
      <button onClick={() => navigate("/")}>go home</button>
    </div>
  );
}

function RequiredAuth({ children }) {
  const auth = useAuth();
  const location = useLocation();

  if (!auth.user) {
    return <Navigate to={"/login"} state={{ from: location }} replace={true} />;
  }

  return children;
}

function User() {
  const auth = useAuth();
  const navigate = useNavigate();

  return (
    <div>
      <h1>User</h1>
      <p>{auth.user?.username}</p>
      <button
        onClick={() => {
          auth.signout(() => navigate("/login"));
        }}
      >
        退出登录
      </button>
    </div>
  );
}

function Login() {
  const auth = useAuth();
  const navigate = useNavigate();
  const location = useLocation();
  const from = location.state?.from.pathname || "/";

  if (auth.user) {
    return <Navigate to={from} />;
  }

  const submit = (e) => {
    const formData = new FormData(e.currentTarget);
    const username = formData.get("username");
    auth.signin({ username }, () => {
      navigate(from, { replace: true });
    });
  };

  return (
    <div>
      <h1>Login</h1>
      <form onSubmit={submit}>
        <input type="text" name="username" />
        <button type="submit">login</button>
      </form>
    </div>
  );
}

function NoMatch() {
  return (
    <div>
      <h1>404</h1>
    </div>
  );
}
----------------文件分割------------------------
const AuthContext = React.createContext();

export function AuthProvider({ children }) {
  const [user, setUser] = React.useState(null);
  const signin = (newUser, callback) => {
    setUser(newUser);
    callback();
  };
  const signout = (callback) => {
    setUser(null);
    callback();
  };

  let value = {
    user,
    signin,
    signout,
  };

  return <AuthContext.Provider value={value} children={children} />;
}

export function useAuth() {
  return React.useContext(AuthContext);
}

在RequiredAuth中,我们做了一次判断,判断当前是否登录

js 复制代码
function RequiredAuth({ children }) {
  const auth = useAuth();
  const location = useLocation();

  if (!auth.user) {
    return <Navigate to={"/login"} state={{ from: location }} replace={true} />;
  }

  return children;
}

Navigate组件是做什么呢?我们可以通过参数得知,它的作用是跳转,是不返回别的东西的。接收什么参数呢?{to, state, replace},他们都是做什么的?

to -- 向哪里跳转

state -- 传递下去的数据

replace -- 到底是history.push一个记录还是history.replace一个记录

为什么要replace替换?因为我明明登录了,点击回退又回到登录页的行为很弱智。

js 复制代码
export default function Navigate({to,state,replace}) {
    const navigate = useNavigate()
    useEffect(() => {
        navigate(to, { replace, state });
    });
    return null
}

并且我们重新修改了useNavigate,让它适配更多功能,而不是简单的to。

js 复制代码
export function useNavigate(){
    //跳转
    const { navigator } = React.useContext(NavigationContext);
    const navigate = React.useCallback(
        (to, options = {}) => {
          if (typeof to === "number") {
            navigator.go(to);
            return;
          }
          (!!options.replace ? navigator.replace : navigator.push)(
            to,
            options.state
          );
        },
        [navigator]
      );
    
      return navigate;
}

这样我们既可以使用usenavigate路由跳转,也可以使用Link标签和Navigate组件进行路由跳转了!

我们已经拥有了一个简单的react-router6,当然这不是全部,以后有机会再继续。

相关推荐
JiaLin_Denny5 小时前
如何在NPM上发布自己的React组件(包)
前端·react.js·npm·npm包·npm发布组件·npm发布包
斯文的孙13 小时前
React JSX:每天都在用,但你真的了解它吗?
前端·react.js
张勇82914 小时前
# React状态管理最佳实践:从原理到2025年主流方案
前端·react.js
小肚肚肚肚肚哦17 小时前
React 源码解读 (初版)
react.js
curdcv_po17 小时前
🔥🔥🔥结合 vue 或 react,去写three.js
前端·react.js·three.js
却尘19 小时前
React状态的人格分裂:当Vibe Coding遇上状态污染,坑你就完了。
前端·react.js·vibecoding
懋学的前端攻城狮1 天前
从 UI = f(state) 到 Fiber 架构:解构 React 设计哲学的“第一性原理”
前端·react.js·前端框架
前端小咸鱼一条1 天前
React中的this绑定
前端·javascript·react.js
前端小咸鱼一条1 天前
React的基本语法和原理
前端·javascript·react.js