【问题标题】:Using React and Redux Hooks, why is my action not firing?使用 React 和 Redux Hooks,为什么我的操作没有触发?
【发布时间】:2019-11-27 15:07:14
【问题描述】:

编辑:已解决!请参阅below

我希望我的 Blog 组件在每次浏览器请求其 URL 时触发 fetchBlog 动作创建者,无论是通过链接还是刷新。我想用 React useEffect Hook 和 React-Redux useDispatchuseSelector Hooks 来做。但是,我的操作仅在点击页面链接时触发;我不明白为什么,即使在阅读了几个解释(如the official docs)之后。

代码如下:

// Everything duly imported, or else VSC would yell at me

export default function Blog() {
  const dispatch = useDispatch();
    // slug is set here with useSelector, this always works
  useEffect(() => {
    dispatch(fetchBlog(slug))
  }, [slug, dispatch]);
  const blog = useSelector((state) => state.blogs[0]);
    // return renders the blog information from the blog constant
    // since the action does not fire, blog is undefined because state.blogs is an empty array
}

我知道,在刷新时,fetchBlog 不会因为 Redux DevTools 而触发,也因为我在那里放了一个debugger。 (并且后端日志没有显示进来的请求。)动作创建者本身和减速器必须在工作;否则,当通过链接访问时,页面将无法正确加载。

编辑:我已经确定 useSelectoruseDispatch 不是问题的根本原因,因为将代码更改为使用 connectmapStateToPropsmapDispatchToProps 会得到相同的结果。问题似乎出在useEffect

【问题讨论】:

  • 组件是否已卸载,也许这就是它之后不触发的原因?
  • 我认为它没有被卸载,因为我仍然得到一个错误:动作没有触发,所以state.blogs是一个空数组,所以data是未定义的,所以阅读@ JSX 部分中的 987654339@ 会抛出 TypeError: Cannot read property 'title' of undefined。但我对此不是很有信心 - 我怎么能 100% 肯定组件已卸载?什么可以卸载它?

标签: javascript reactjs react-redux react-hooks


【解决方案1】:

我认为问题在于您正在返回对调度的调用。从 useEffect 返回的函数是清理函数,所以我认为这不会在挂载或更新时运行 - 仅在卸载之前运行。试试这个:

export default function Blog() {
  // ...
  // Don't return from useEffect. Just call dispatch within the body.
  useEffect(() => {
    dispatch(fetchBlog(slug);
  }, [slug, dispatch]);
  // ...

}

https://reactjs.org/docs/hooks-reference.html#cleaning-up-an-effect

【讨论】:

  • 你说得对,我不应该从useEffect 内部返回,谢谢。不幸的是,这仍然不能解决问题 - useEffect 本身并没有在刷新时被触发。尽管如此,我还是感谢您的意见。
  • @brunoparga 尝试使用空数组运行它,即使它仍然不起作用,您也可以排除问题出在通过 useEffect 数组传递的参数的可能性。
  • 在控制台上给了我Line 12:6: React Hook useEffect has missing dependencies: 'dispatch' and 'slug'. Either include them or remove the dependency array react-hooks/exhaustive-deps
  • @brunoparga 对不起,我认为有一个额外的括号。您可以发布更新的代码吗?
  • 不幸的是,我需要更多代码来帮助您。如果你有一个 repo 我可以看看我可能可以帮助调试。
【解决方案2】:

我想澄清问题是什么,@Trace 引导我找到了。

useEffect 在刷新时没有被调用,因为它在组件渲染/返回之后被调用。刷新时,状态(包括博客数据)丢失;而不是返回,而是抛出 TypeError,因为 data.title 不存在。所以useEffect 永远没有机会被调用并获取博客的内容。

解决办法是这样的:

export default function Blog() {
  // ...
  useEffect(/* ... */)
  const blog = useSelector((state) => state.blogs[0]);
  if (!blog) {
    return <p>Loading...</p>
  }
  // return actual blog contents here
}  

所以现在确实调用了fetchBlog,更新blog 并呈现内容。

【讨论】:

  • 这将得到一个无效的钩子调用。 useSelector钩子应该在组件体级别调用?
【解决方案3】:

我不清楚蛞蝓是从哪里来的。
理论上useEffect 在每次渲染后运行。如果有多个参数,它将在第二个参数中传递的数组参数之一发生更改时运行回调。

要么创建一个useEffect,并将空数组作为第二个参数,以“一次”运行它(例如,当你刷新时)或检查 slug 值。

检查回购后编辑:

  • 它不起作用,因为 useEffect 在渲染之后运行(尽管有人反对它,但我的回答中包含了它)。如果之前抛出异常(在本例中为空指针),则调度调用只会在之后发生,或者根本不会发生。
  • 您可以使用match 从 react-router 获取 slug,可能对您很方便。

    export default function Blog({ match }) {
        const slug = match.params.slug;
    etc
    
  • git repo 显示了如何将 dispatch as 作为数组参数添加到 useEffect,这不是必需的。

【讨论】:

  • 我认为问题在于,在使用新的 slug 再次安装之前,组件可能并不总是卸载。所以 op 想要保持 use effect 的第二个参数不变。
  • @pizza-r0b 我不知道你为什么说卸载,因为用户清楚地谈到刷新页面,这意味着所有组件都被重新加载。
  • “通过链接或刷新”
  • “但是,我的操作仅在点击页面链接时触发”+“我知道刷新时,fetchBlog 不会触发”
  • 感谢您的意见!我知道蛞蝓没问题,我可以记录它,它显示没问题。我更改了代码,以便传递给useEffect 的回调都调用fetchBlog 并返回相同的调用。这样,在卸载时将调用返回值。这并不能解决问题。我还从 deps 数组中删除了 slug,以及删除了数组本身,我得到的只是一个警告,它们丢失了。
猜你喜欢
  • 2020-05-22
  • 1970-01-01
  • 2019-05-08
  • 2016-06-14
  • 1970-01-01
  • 2020-01-21
  • 2021-07-03
  • 2023-03-31
  • 2020-08-23
相关资源
最近更新 更多