从 React Router 数据路由器操作调用钩子

dig*_*eed 4 typescript react-router-dom

我正在使用 React Router 6.4.3 和新的数据路由器。

第三方身份验证库通过挂钩公开身份验证上下文和登录函数,例如:

const { AuthenticationContext, login } = useAuthentication();
Run Code Online (Sandbox Code Playgroud)

我已经设法AuthenticationContext通过使用 中的无路径路由将路由包装到 中createBrowserRouter

但是,我无法理解如何利用路由操作来执行登录并随后重定向用户。由于配置和操作现在位于功能组件之外,因此我无法使用该useAuthentication钩子。

我的配置如下:

import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { AuthProvider } from 'auth';
import Login, { action as loginAction } from './routes/login';

const router = createBrowserRouter([
    {
        element: <AuthProvider />,
        children: [
            {
                path: '/login',
                element: <Login />,
                action: loginAction,
            },
        ],
    },
]);

function App() {
    return (
        <RouterProvider router={router} />
    );
}
Run Code Online (Sandbox Code Playgroud)

目前loginAction只有一个存根:

const action = async ({ request, params }) => {
    const formData = await request.formData();
    const updates = Object.fromEntries(formData);

    // How to invoke login() method exposed by useAuthentication() hook here?

}
Run Code Online (Sandbox Code Playgroud)

AuthenticationContext相关方法大致如下所示:

const loginApi = async (email, password) => {
   // ajax call to login endpoint
}

const AuthContext = React.createContext(null);

const AuthProvider = () => {
    const [jwt, setJwt] = useState(null);
    const navigate = useNavigate();

    const login = async (email, password) => {
        const jwt = await loginApi(email, password);
        setJwt(jwt);
        navigate('/dashboard');
    }

    const contextValue = {
        jwt,
        login: handleLogin,
    }
 
    return (
        <AuthContext.Provider value={contextValue}>
            <Outlet />
        </AuthContext.Provider>
    );
}

const useAuth = () => {
    return useContext(AuthContext);
}

export default AuthProvider;
export { useAuth };
Run Code Online (Sandbox Code Playgroud)

有没有一种方法可以在不接触身份验证库的情况下使其与数据路由器一起工作?

Dre*_*ese 6

您很可能需要稍微重构代码以允许App组件使用useAuthentication挂钩,以便它可以访问该login函数,以便将其传递给处理程序loginAction

例子:

'./路线/登录'

import { redirect } from "react-router-dom";

const action = ({ login }) => async ({ request, params }) => {
  const formData = await request.formData();
  const updates = Object.fromEntries(formData);

  // call login, and redirect upon success
  await login(...);
  ...
  redirect('/dashboard');
};
Run Code Online (Sandbox Code Playgroud)

应用程序

import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import Login, { action as loginAction } from './routes/login';

function App() {
  const { login } = useAuthentication();

  const router = createBrowserRouter([
    ....,
    {
      path: '/login',
      element: <Login />,
      action: loginAction({ login }),
    },
    ....
  ]);

  return (
    <RouterProvider router={router} />
  );
}
Run Code Online (Sandbox Code Playgroud)

索引.js

import { AuthProvider } from 'auth';

...

<AuthProvider>
  </App />
</AuthProvider>
Run Code Online (Sandbox Code Playgroud)

认证上下文

const AuthContext = React.createContext(null);

const AuthProvider = ({ children }) => {
  const [jwt, setJwt] = useState(null);

  const login = async (email, password) => {
    const jwt = await loginApi(email, password);
    setJwt(jwt);
    // return success/fail for login action handler
  }

  const contextValue = {
    jwt,
    login: handleLogin,
  }
 
  return (
    <AuthContext.Provider value={contextValue}>
      {children}
    </AuthContext.Provider>
  );
}
Run Code Online (Sandbox Code Playgroud)