【问题标题】:what is the best way to use react router V6 navigation with redux and redux thunk actions?使用带有 redux 和 redux thunk 操作的反应路由器 V6 导航的最佳方法是什么?
【发布时间】:2022-08-23 02:43:55
【问题描述】:

我正在使用反应-v17, 和反应还原V7 和反应路由器 V6, 搜索和阅读许多文章,我找不到使用 V6 挂钩以编程方式在 redux 操作中导航的方法,因为挂钩只能在组件内部调用,这就是我所拥有的

注册页面.jsx

import React, { Component } from \'react\'
import { useParams, useNavigate } from \'react-router-dom\'
import { useEffect, useState } from \'react\'
import { useDispatch, useSelector } from \'react-redux\'

import { LockClosedIcon } from \'@heroicons/react/solid\'
import Loader from \'react-loader-spinner\'

import { registerUser } from \'../../../state_man/store/register\'

const RegisterForm = (props) => {
  const [registerFields, setRegisterFields] = useState({})
  const [errors, setErrors] = useState({})
  const [validInput, setValidInput] = useState({})
  const [loading, setLoading] = useState(false)

  let navigate = useNavigate()
  let params = useParams()

  let auth = useSelector((state) => state.auth)
  let mainUi = useSelector((state) => state.UI.mainUI)
  let registerUi = useSelector((state) => state.UI.registerPage)

  const dispatch = useDispatch()

  const { isLoggedIn } = auth

const onRegisterUser = (e) => {
    e.preventDefault()

    const credentials = {
      username: registerFields[\'username\'],
      [\'phone\']: registerFields[\'phone\'],
      email: registerFields[\'email\'],
      region: registerFields[\'region\'],
      password: registerFields[\'password\'],
      address: registerFields[\'address\'],
      client_name: registerFields[\'client_name\'],
    }
    dispatch(registerUser(credentials))
return (

    // my form is so long, i made it short just for demonstration purposes! 
    <form>
      <input type=\'text\' />
      <input type=\'passowrd\' />
      <button
        onClick={(e) => {
          // here i call the function that does the registration ,
 //that included calling a function that dispatches API action,
          onRegisterUser(e)
        }}
      ></button>
    </form>
  )

  }

在我的状态管理模块中,我创建了一个调度 API 操作的函数,什么

注册.js

const url = \'/client\'
export const registerUser = (credentials) => {

  return apiActionCreators.apiCallBegan({
    url,
    method: \'post\',
    data: credentials,
    onStart: START_LOADING.type,
    onEnd: END_LOADING.type,
    onSuccessFunc: (data) => (dispatch, store) => {
      dispatch(USER_REGISTERED(data))
      dispatch(CLEAR_MAIN_ERROR())
      // i want to take the user to a specific page using something like navigate(\"menu\")
    },
    onErrorFunc: (error) => (dispatch, store) => {
      dispatch(ADD_MAIN_ERROR(error))
    },
  })
}

正如我评论的那样,我想在“onSuccessFunc”内的该操作中执行一个函数,以便将用户带到特定页面 , 我知道我可以制作一个减速器并将其用于导航,我将带有有效负载的动作发送到我想要导航的地方,并且在 HOC 中,我检查是否有导航到的路径, 如果我是真的,我会清除它并导航,就像这样!

let navigation = useSelector((state) => state.navigation)

  useEffect(() => {
    if (navigation.path) {
      dispatch(
        navigationActions.CLEAR_NAVIGATION_PATH()
      )
      navigate(\'/navigation.path\')
    }
  }, []) 

这似乎是一个很好的解决方案,我认为可能有很多 DRY 和缺点, 做这个的最好方式是什么!你看到我的解决方案有什么缺点吗!记住我使用的是 react-router V6!谢谢。

  • stackoverflow.com/a/70000286/8690857stackoverflow.com/a/70012117/8690857 是否回答您的问题?第一个是在路由器和 React 应用程序之外公开编程导航的通用解决方案,第二个是更具体的用例,您可以将 axios 拦截器中的用法替换为异步操作创建者中的用法。
  • 是的,他们这样做了,但我想我会找到一个中间件或 RRDv6 本身提供的东西,而且他们所拥有的似乎是“不稳定的”,我发现创建我的钩子的第一个答案也很好,所以谢谢你,我将接受第一个答案,并发表评论。
  • 如果您决定回滚到 RRDv5,connected-react-router 是一个可靠的解决方案,尽管希望有一个更新以允许与 RRDv6 兼容。如果他们这样做,可能值得关注。

标签: reactjs react-redux react-router-dom redux-thunk


【解决方案1】:

您最好直接在回调中进行导航。 您可以利用 Hooks 规则:Call Hooks from custom Hooks

// register.js or useRegister.js

export const useRegisterUser = () => {

  const navigate = useNavigate();

  const doRegister = (credentials) => {
    return apiActionCreators.apiCallBegan({
    url,
    method: 'post',
    data: credentials,
    onStart: START_LOADING.type,
    onEnd: END_LOADING.type,
    onSuccessFunc: (data) => (dispatch, store) => {
      dispatch(USER_REGISTERED(data))
      dispatch(CLEAR_MAIN_ERROR())
      // allowed since it's inside a hook
      navigate("menu")
    },
    onErrorFunc: (error) => (dispatch, store) => {
      dispatch(ADD_MAIN_ERROR(error))
    },
  })
}

return {
    doRegister 
}

}
// registerPage.js

import { useRegisterUser } from './register.js'
// other imports 

const RegisterForm = (props) => {

  const { doRegister } = useRegisterUser()

// other stuffs
// grab credentials

    dispatch(doRegister(credentials))

// other stuffs

return (<></>)
}

【讨论】:

    【解决方案2】:

    在搜索和阅读了一些 cmets 之后,我找到了 3 个可能的解决方案, 第一个是第一个答案,但我不太习惯使用它,因为我不知道钩子的实现细节,我试过了,效果很好, 第二个选项是创建您自己的CustomRouter,给它一个您创建的history 对象,并按照此处指定的方式更改您所做的历史对象: https://stackoverflow.com/a/70012117/8690857,感谢 Drew 指出。 第三种是使用可以从 RRDv6 导入的对象,称为 unstable_HistoryRouter,您也可以在这里找到它https://stackoverflow.com/a/70012117/8690857

    【讨论】:

      【解决方案3】:

      对我来说,我试图等待使用createAsyncThunk 创建的函数的结果。我知道使用dispatch,但不确定如何对成功或失败做任何事情。我在 redux 文档here 中找到了我的答案

      相关部分:

      const handleUpdateUser = async (userData) => {
        const resultAction = await dispatch(updateUser(userData))
        if (updateUser.fulfilled.match(resultAction)) {
          const user = resultAction.payload
          showToast('success', `Updated ${user.name}`)
        } else {
          if (resultAction.payload) {
            // Since we passed in `MyKnownError` to `rejectValue` in `updateUser`, the type information will be available here.
            // Note: this would also be a good place to do any handling that relies on the `rejectedWithValue` payload, such as setting field errors
            showToast('error', `Update failed: ${resultAction.payload.errorMessage}`)
          } else {
            showToast('error', `Update failed: ${resultAction.error.message}`)
          }
        }
      }
      

      更具体地说,使用updateUser.fulfilled.match(resultAction)

      我用它在登录后进行导航。这是我的登录提交功能的样子。

        const handleLoginSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
          event.preventDefault();
          const formData = new FormData(event.currentTarget);
          const email: string = formData.get('email') as string;
          const password: string = formData.get('password') as string;
          if (!email || !password) {
            return;
          } else {
            const resultAction = await dispatch(loginAsync({ email, password }))
            if (loginAsync.fulfilled.match(resultAction)) {
              navigate('/dashboard');
            } else if (loginAsync.rejected.match(resultAction)) {
              console.log('Failed!');
            }
          }
        }
      

      【讨论】:

        猜你喜欢
        • 2020-08-24
        • 2018-09-04
        • 2020-06-16
        • 2016-06-12
        • 1970-01-01
        • 2019-08-05
        • 1970-01-01
        • 2019-06-15
        • 1970-01-01
        相关资源
        最近更新 更多