react-hooks:从 useEffect 分派动作

IT技术 javascript reactjs redux redux-saga
2021-04-21 09:01:47

我的文件夹结构:

|--App
  |--Components
    |--PageA.js
    |--PageB.js
    |--PageC.js
  |--common-effects
    |--useFetching.js

我正在重构我的代码以使用 react hooks从 API 获取数据我想从useFetching.js中的useEffect调度一个saga中间件拦截的动作仅当组件(PageAPageBPageC)安装时才应分派该操作

我正在使用reduxreact-reduxredux-saga

页面A.js :

function(props) {
  useFetching(actionParams)
  //....//
}

PageBPageC组件的类似代码

我已经抽象了可重用代码以在useFetching Custom hook 中获取数据

使用Fetching.js

const useFetching = actionArgs => {
  useEffect( () => {
    store.dispatch(action(actionArgs)); // does not work
  })
}

我不知道如何dispatchuseFetching 中访问 redux 我试了一下,useReducer效果不错,但传奇错过了动作。

5个回答

使用 react-redux 钩子的版本:

你甚至可以通过使用useDispatchfrom react-redux来完全切断连接功能

export default function MyComponent() {
  useFetching(fetchSomething);

  return <div>Doing some fetching!</div>
}

使用您的自定义挂钩

import { useDispatch } from 'react-redux';

const useFetching = (someFetchActionCreator) => {
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(someFetchActionCreator());
  }, [])
}

编辑:按照@yonga-springfield 的建议从自定义钩子中删除调度

注意: React 保证 dispatch 函数标识是稳定的并且不会在重新渲染时改变。这就是为什么从 useEffect 或 useCallback 依赖项列表中省略是安全的。

将 dispatch 放入 useEffect 时出现错误: React Hook useEffect has a missing dependency: 'dispatch'. Either include it or remove the dependency array react-hooks/exhaustive-deps
2021-05-22 09:01:47
是否dispatch应该包含在 useEffect 的依赖数组中?
2021-05-28 09:01:47
“React 保证调度函数身份是稳定的”来源?我在任何地方都找不到这个。
2021-06-08 09:01:47
@马丁。谢谢,但我看到的是dispatch fromuseReducer是稳定的,但是dispatchfrom useDispatchfromreact-redux呢?
2021-06-13 09:01:47
@pianoman102 techincaly,是的,你应该这样做。即使那里的注释提到它的身份是稳定的,不会改变;这并不意味着你应该忽略它,如果使用 CRA 将继续抛出 lint 规则。此处描述了更多上下文:github.com/facebook/create-react-app/issues/...
2021-06-17 09:01:47

您需要传递绑定动作创建者或dispatch对钩子的引用这些将来自一个连接的组件,就像你通常使用 React-Redux 一样:

function MyComponent(props) {
    useFetching(props.fetchSomething);

    return <div>Doing some fetching!</div>
}

const mapDispatch = {
    fetchSomething
};

export default connect(null, mapDispatch)(MyComponent);

然后钩子应该调用效果中的绑定动作创建者,这将相应地分派动作。

另外,请注意,每次重新渲染组件时,您当前的钩子都会重新运行效果,而不仅仅是第一次。您需要像这样修改钩子:

const useFetching = someFetchActionCreator => {
  useEffect( () => {
    someFetchActionCreator();
  }, [])
}
我的所有组件都使用一个 action export const fetchData = payload => ({ type: 'FETCH_DATA' })sagas然后将通过分派相应的动作将值存储在页面的适当减速器中。根据您的解决方案,我必须传递引用以从每个组件分派。
2021-06-01 09:01:47
我做了一些调整,它有效。万分感谢!但是我仍然觉得将每个组件的 dispatch 引用传递给自定义钩子比我在 HOC 中可以做到的有点重复。
2021-06-06 09:01:47
您想要调度的任何操作,例如fetchData您刚刚在该评论中编写函数。
2021-06-07 09:01:47
考虑到我不想专门为我的钩子将动作创建者连接到我的组件。有任何想法吗?
2021-06-10 09:01:47
我相应地更改了代码,但saga 仍然yield take('FETCH_DATA');无法拦截此操作
2021-06-20 09:01:47

这只是为了对@Alex Hans 的回答进行一些优化。

根据此处的文档自定义 Hook 是一个 JavaScript 函数,其名称以“use”开头,并且可以调用其他 Hook。

考虑到这一点,我们不需要将调度函数的引用作为参数发送到 useFetching 钩子,而是简单地不发送它,而是简单地从带有适当导入的 useFetching 钩子中使用它。

这是我的意思的摘录。

import { useDispatch } from 'react-redux';

const useFetching = (someFetchActionCreator) => {
    const dispatch = useDispatch()

    useEffect(() => {
    dispatch(someFetchActionCreator());
  }, [])
}

我无法确定这个示例是否适合您的代码库,但只是试图解释这篇文章背后的想法/概念。

希望这对任何未来的人都有帮助。

在 useEffect(() => {...}, [dispatch]) 中传递调度的依赖参数很重要
2021-06-07 09:01:47

Alex Hans 对 dispatch 做出了正确的决定,但是为了消除对 api 的请求循环,您可以指定对 dispatch 的依赖(我使用了Redux Toolkit

  import React, { useEffect } from 'react'
  import { useDispatch } from 'react-redux'
  import axios from 'axios'
  import { getItemsStart, getItemsSuccess, getItemsFailure } from '../features/itemsSlice'

  const fetchItems = () => async dispatch => {
    try {
      dispatch(getItemsStart());
      const { data } = await axios.get('url/api')
      dispatch(getItemsSuccess(data))
    } catch (error) {
      dispatch(getItemsFailure(error))
    }
  }

  const PageA = () => {
    const dispatch = useDispatch()
    const { items } = useSelector(state => state.dataSlice)
   
    useEffect(() => {
       dispatch(fetchItems())
    }, [dispatch])

    return (
      <ul>
         {items.map(item => <li>{item.name}</li>}
      </ul> 
    )
  }
  
  export default PageA

在 useEffect(() => {...}, [dispatch]) 中传递调度的依赖参数很重要

useEffect(() => {
   fetchData();
 }, []);

 async function fetchData() {
   try {
     await Auth.currentSession();
     userHasAuthenticated(true);
   } catch (e) {
     if (e !== "No current user") {
       alert(e);
     }
   }
   dispatch(authentication({ type: "SET_AUTHING", payload: false }));
 }
欢迎使用堆栈溢出!考虑添加一些关于您发布的代码如何/为什么工作的解释。
2021-06-13 09:01:47