useNavigate 会阻止 createAsyncThunk、redux 工具包中的其余内容

useNavigate blocks rest of the content in createAsyncThunk, redux toolkit

我正在尝试在 redux 工具包中访问 createAsyncThunk 中的 useNavigate hooke,如下所示:

export const onHandleBookmark = createAsyncThunk('articles/example', async (id: string, { dispatch, getState }) => {
    const navigate = useNavigate()
    console.log('DDD')
    console.log('LLL')
    //rest of the processing
})
    

不幸的是,没有显示任何日志,因为它在第一行执行时耗尽。有人可以告诉我出了什么问题吗?

不允许在组件外部调用像 useNavigate 这样的挂钩 - 在这种情况下,它可能会抛出错误。并不是说这与 Redux 或 createAsyncThunk 无关——它会在组件之外的任何地方发生。

如果您需要在 Redux 组件之外访问 navigate,请参阅 Navigating without the navigation prop

选项A(更简单,需要redux-toolkit):

当使用createAsyncThunkapi时,返回的函数默认是promisified。您可以使用 unwrap() 方法等待 promise 解析(我猜是受 Rust 启发……)。当 promise 被 resolve 时,它​​可以与 then() 调用进一步链接,因此您可以从那里导航:

import { useSelector, useDispatch } from "react-redux"
import { useNavigate } from "react-router"
import { logout } from "../store/auth"

const LogoutButton = () => {
  const dispatch = useDispatch()
  const navigate = useNavigate()

  return (  
    <button 
      onClick={() => 
        dispatch(logout()) 
          .unwrap() // <-- async Thunk returns a promise, that can be 'unwrapped')
          .then(() => navigate("/"))
      }
    >
      Log out
    </button>
  )
}

选项 B(更多 complected,但适用于原版 react-redux):

虽然您不能在 React 组件外部调用 useNavigate(),但您可以将其作为参数传递给 dispatch() 调用:

示例组件:

import { useSelector, useDispatch } from "react-redux"
import { useNavigate } from "react-router"
import { logout } from "../store/auth"

const LogoutButton = () => {
  const dispatch = useDispatch()
  const navigate = useNavigate() // <-- Grab the 'navigate' reference

  return (  
    <button 
      onClick={() => dispatch(logout(navigate))} // <-- Pass 'navigate' as argument
    >
      Log out
    </button>
  )
}

Redux 异步 Thunk

然后你可以调用在 thunk 中作为参数传递的函数引用:

export const logout = createAsyncThunk(
  "[auth] logout",
  async (navigate) => {
    const response = await axios.get("auth/logout")
    if (response) {
      navigate("/")
      return response
    }
})