将 react router V6 导航与 redux 和 redux thunk 操作一起使用的最佳方法是什么?

what is the best way to use react router V6 navigation with redux and redux thunk actions?

我正在使用 React-v17react-redux V7 制作一个 React 应用程序(不是 react-native),以及 React Router V6, 搜索和阅读许多文章,我找不到使用 V6 挂钩在 redux 操作中以编程方式导航的方法,因为挂钩只能在组件内部调用,这就是我所拥有的

registerPage.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 动作的函数,什么

register.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!谢谢。

您最好直接在回调中进行导航。 您可以利用 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 (<></>)
}

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