React Hooks:useEffect的分派动作

Har*_*rma 7 javascript reactjs redux redux-saga

我的文件夹结构:

|--App
  |--Components
    |--PageA.js
    |--PageB.js
    |--PageC.js
  |--common-effects
    |--useFetching.js
Run Code Online (Sandbox Code Playgroud)

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

我正在使用reduxreact-reduxredux-saga

PageA.js

function(props) {
  useFetching(actionParams)
  //....//
}
Run Code Online (Sandbox Code Playgroud)

PageBPageC组件的类似代码。

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

useFetching.js

const useFetching = actionArgs => {
  useEffect( () => {
    store.dispatch(action(actionArgs)); // does not work
  })
}
Run Code Online (Sandbox Code Playgroud)

我不知道如何dispatchuseFetching中访问redux 。我尝试了一下useReducer,但sagas错过了动作。

Ale*_*ans 12

使用react-redux钩子的版本:

您甚至可以通过使用useDispatchreact-redux 完全切断连接功能:

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

  return <div>Doing some fetching!</div>
}
Run Code Online (Sandbox Code Playgroud)

用你的自定义钩子

import { useDispatch } from 'react-redux';

const useFetching = (someFetchActionCreator) => {
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(someFetchActionCreator());
  }, [])
}
Run Code Online (Sandbox Code Playgroud)

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

注意: React保证调度功能的身份是稳定的,并且在重新渲染时不会改变。这就是为什么可以安全地从useEffect或useCallback依赖项列表中省略的原因。

  • 将调度放入 useEffect 时出现错误:```React Hook useEffect 缺少依赖项:'dispatch'。要么包含它,要么删除依赖数组react-hooks/exhaustive-deps``` (10认同)
  • 应该在useEffect的依赖项数组中包含`dispatch`吗? (6认同)
  • @马丁。谢谢,但我看到的是 `useReducer` 中的 `dispatch` ** 是稳定的,但是 `react-redux` 中的 `useDispatch` 中的 `dispatch` 又如何呢? (2认同)

小智 9

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

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

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

这是我的意思的摘录。

import { useDispatch } from 'react-redux';

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

    useEffect(() => {
    dispatch(someFetchActionCreator());
  }, [])
}
Run Code Online (Sandbox Code Playgroud)

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

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


mar*_*son 8

您将需要传递绑定动作创建者或dispatch对钩子的引用。这些将来自连接的组件,与通常使用React-Redux的相同:

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

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

const mapDispatch = {
    fetchSomething
};

export default connect(null, mapDispatch)(MyComponent);
Run Code Online (Sandbox Code Playgroud)

然后,该挂钩应调用效果中的绑定动作创建者,该动作创建者将相应地调度该动作。

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

const useFetching = someFetchActionCreator => {
  useEffect( () => {
    someFetchActionCreator();
  }, [])
}
Run Code Online (Sandbox Code Playgroud)

  • 考虑到我不希望将动作创建者连接到专门用于我的钩子的组件。有任何想法吗? (2认同)

Fre*_*imb 7

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
Run Code Online (Sandbox Code Playgroud)

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