Javascript 反应钩子:从useEffect分派操作
我的文件夹结构:Javascript 反应钩子:从useEffect分派操作,javascript,reactjs,redux,redux-saga,Javascript,Reactjs,Redux,Redux Saga,我的文件夹结构: |--App |--Components |--PageA.js |--PageB.js |--PageC.js |--common-effects |--useFetching.js 我正在重构代码,使用react从API获取数据。 我想从useffetching.js中的useffect发送一个操作,该操作被saga中间件截获。仅当组件(PageA、PageB、PageC)装入时,才应分派操作 我正在使用redux、react re
|--App
|--Components
|--PageA.js
|--PageB.js
|--PageC.js
|--common-effects
|--useFetching.js
我正在重构代码,使用react从API获取数据。
我想从useffetching.js中的useffect发送一个操作,该操作被saga中间件截获。仅当组件(PageA、PageB、PageC)装入时,才应分派操作
我正在使用redux、react redux和redux saga
PageA.js:
PageB和PageC组件的类似代码
我已经抽象了可重用代码,以便在useFetching
customhook中获取数据
useFetching.js
我不知道如何在useFetching中访问redux
dispatch
。我尝试了useReducer
效果,但是传奇没有成功。您需要将绑定动作创建者或对dispatch
的引用传递给钩子。这些将来自连接的组件,与您通常使用React-Redux相同:
功能MyComponent(道具){
使用抓取(道具。抓取某物);
回来做一些抓取!
}
常量映射分派={
吸引
};
导出默认连接(null,mapDispatch)(MyComponent);
然后,钩子应该在effect中调用绑定的动作创建者,后者将相应地分派动作
另外,请注意,当前挂钩将在每次重新渲染组件时重新运行效果,而不仅仅是第一次。您需要修改钩子,如下所示:
const useFetching=someFetchActionCreator=>{
useffect(()=>{
someFetchActionCreator();
}, [])
}
使用react-redux挂钩的版本:
您甚至可以使用react redux的useDispatch
完全切断连接功能:
export default function MyComponent() {
useFetching(fetchSomething);
return <div>Doing some fetching!</div>
}
编辑:根据@yonga springfield的建议,从自定义钩子中删除了调度
注意:React保证分派函数标识是稳定的,并且在重新渲染时不会更改。这就是为什么从useEffect或useCallback依赖项列表中省略是安全的。这只是为了给@Alex Hans的答案带来一些优化 根据文件。自定义钩子是一个JavaScript函数,其名称以“use”开头,可以调用其他钩子 考虑到这一点,我们不需要将对dispatch函数的引用作为参数发送到useFetching钩子,而是不发送它,而是通过适当的导入从useFetching钩子中使用它 这是我的意思的摘录
import { useDispatch } from 'react-redux';
const useFetching = (someFetchActionCreator) => {
const dispatch = useDispatch()
useEffect(() => {
dispatch(someFetchActionCreator());
}, [])
}
我不能确定这个例子是否适合你的案例,但我只是试图解释本文背后的想法/概念
希望这对未来的任何参与者都有帮助。Alex Hans在分派方面的决策是正确的,但为了消除api的请求循环,您可以指定对分派的依赖性(我使用过)
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 }));
}
import React,{useffect}来自“React”
从“react redux”导入{useDispatch}
从“axios”导入axios
从“../features/itemsSlice”导入{getItemsStart、GetItemsAccess、getItemsFailure}
const fetchItems=()=>异步调度=>{
试一试{
调度(getItemsStart());
const{data}=wait axios.get('url/api')
调度(GetItemsAccess(数据))
}捕获(错误){
调度(getItemsFailure(错误))
}
}
常数PageA=()=>{
const dispatch=usedpatch()
const{items}=useSelector(state=>state.dataSlice)
useffect(()=>{
分派(fetchItems())
}[快讯])
返回(
{items.map(item=>- {item.name}
}
)
}
导出默认页面A
在useffect(()=>{…},[dispatch])中传递dispatch的依赖参数是很重要的。我不认为钩子应该用于像那样的arrow函数中。另外,如果你想使用redux,他们已经为此设置了钩子:通过arrow函数,你是说,
constuseffetching=actionArgs=>{}
,如果我没有错的话?是的,但看起来我错了。我的所有组件都使用一个动作export const fetchData=payload=>({type:'FETCH_DATA'})
sagas
然后将通过分派相应的操作将值存储在页面的相应减缩器中。根据您的解决方案,我必须从每个组件传递分派的引用。您要分派的任何操作,如刚才在该注释中编写的fetchData
函数。我更改了代码相应地,但仍然是sagayield take('FETCH_DATA'))但是,我仍然觉得通过引用从每个组件到自定义钩子的传递比我在HOCH中的重复有点重复。考虑到我不想将动作创建器特别连接到我的钩子上。有什么想法吗?应该<代码>调度是否包含在useEffect的依赖项数组中?在useEffect中放置dispatch时,我遇到一个错误:React-Hook useEffect缺少依赖项:“dispatch”。请包含它或删除依赖项数组React-hooks/deps
@pianoman102-Technicaly,是的。即使注释中提到它的id实体是稳定的,不会改变;这并不意味着yo-ushoudl会忽略它,如果使用CRA,lint规则将继续抛出。这里描述了更多上下文:“React保证分派函数标识是稳定的”源代码?我找不到任何地方。“马丁。谢谢,但是我看到的是,<代码>调度<代码> > <代码>用户> <代码>是稳定的,但是关于<代码>调度< >代码>从<代码>使用调度> /代码>从<代码> Read ReDux < /代码>?欢迎添加关于您如何发布代码工作的原因的解释。在useffect(()=>{…},[dispatch])中传递dispatch的依赖参数非常重要,太棒了!谢谢!
import { useDispatch } from 'react-redux';
const useFetching = (someFetchActionCreator) => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(someFetchActionCreator());
}, [])
}
import { useDispatch } from 'react-redux';
const useFetching = (someFetchActionCreator) => {
const dispatch = useDispatch()
useEffect(() => {
dispatch(someFetchActionCreator());
}, [])
}
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 }));
}
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