关闭模式后刷新使用自定义挂钩获取的数据
Posted
技术标签:
【中文标题】关闭模式后刷新使用自定义挂钩获取的数据【英文标题】:Refreshing data fetched with a custom hook after closing a modal 【发布时间】:2020-10-14 16:30:16 【问题描述】:我正在使用挂钩在我的应用中获取数据。钩子看起来像这样:
const initialState =
response: null,
loading: true,
error: null
const useGetFetch(url, token, user, parser) =>
const [state, dispatch] = useReducer(fetchReducer, initialState)
useEffect (() =>
if(user)
fetch(...)
.then((data)=> data.json())
.then(dispatch(...)) // setting the state here
.catch((error) => dispatch(...)) // set error state
, [user])
return [state.response, state.loading, state.error]
具体来说,我在表单组件中使用了这个钩子,以获取一些数据以用作选择元素中的选项。
但是,我需要能够让用户即时添加新选项。为方便起见,我在选择元素旁边创建了一个按钮。如果用户按下此按钮,将弹出一个模态框,其中包含另一个表单,可以创建新选项。这个新选项通过 post 请求发送到服务器,如果成功,模式关闭。
我面临的问题是,模式关闭后,我无法更新使用自定义数据获取挂钩获取的初始数据,除非我刷新页面。有没有办法在不触发页面刷新的情况下以某种方式实现这一点?
我最初的预感是使用回调函数并将其传递给useGetFetch
并将其绑定到useEffect
挂钩。然后我可以将它传递给模态中的表单并在成功提交后调用该函数,但这不起作用。
我正在寻找的另一个选项是 useCallback
挂钩,但我目前对它的理解还不够深入,无法知道它是否有用。
编辑
具体我做的是在父组件之外创建一个触发函数:
const trigger = () => console.log("click")
将其绑定到 fetch 挂钩:
const useGetFetch(url, token, user, parser, trigger) =>
const [state, dispatch] = useReducer(fetchReducer, initialState)
useEffect (() =>
if(user)
fetch(...)
.then((data)=> data.json())
.then(dispatch(...)) // setting the state here
.catch((error) => dispatch(...)) // set error state
, [user, trigger])
return [state.response, state.loading, state.error]
并将其传递给父组件内部的子组件:
const trigger = () => console.log("click")
const Parent = () =>
// load a bunch of stuff
// ...
const show, toggle = useModal()
const [optionsData, Loading, Error] = useGetFetch(
optionsUrl,
token,
user,
parser,
trigger
)
// ...
return (
<div>
// ...
<button
onClick=(e) =>
e.preventDefault()
toggle()
>
Add
</button>
<Modal show=show toggle=toggle>
<ModalForm
show=show
toggle=toggle
trigger=trigger
></ModalForm>
</Modal>
// ...
<div>
)
在成功执行发布请求后调用ModalForm
内部触发器。关闭模态后,数据不会更新。我的猜测是,在ModalForm
内部调用 trigger 会在useGetFetch
内部触发useEffect
,但它似乎不会那样工作。
【问题讨论】:
好吧,据我了解,问题是您想在用户关闭模式时重新获取数据?我说的对吗? 是的,你是对的。 【参考方案1】:如果清楚地理解您的问题,我认为您要做的是在用户关闭模式时强制重新获取。
您可以通过触发useGetFetch
钩子内的强制重新渲染来做到这一点,如下所示:
const useGetFetch(url, token, user, parser) =>
const [state, dispatch] = useReducer(fetchReducer, initialState)
// calling refetch will force a rerender on the hook
const [shouldRefetch, refetch] = useState();
useEffect (() =>
if(user)
fetch(...)
.then((data)=> data.json())
.then(dispatch(...)) // setting the state here
.catch((error) => dispatch(...)) // set error state
, [user, shouldRefetch]); // note the dep array
// returning the refetch functions so we can call the refetch() on modal close.
return [state.response, state.loading, state.error, refetch];
这就是useGetFetch,现在你将像这样使用钩子:-
const Parent = () =>
const show, toggle = useModal();
// notice the refetch method
const [optionsData, Loading, Error, refetch] = useGetFetch(
optionsUrl,
token,
user,
parser
);
return (
<div>
<button
onClick=e =>
e.preventDefault();
toggle();
>
Add
</button>
<Modal show=show toggle=toggle>
<ModalForm
show=show
toggle=toggle
trigger=() =>
// probably onClose would be better name instead of `trigger`
// calling the refetch method with empty object, this will cause rerender
refetch();
></ModalForm>
</Modal>
</div>
);
;
【讨论】:
欢迎您,乐于助人:D【参考方案2】:我认为你在 useEffect 函数中缺少 ,
这就是为什么你得到 X 不是函数错误
useEffect (() =>
if(user)
fetch(...)
.then((data)=> data.json())
.then(dispatch(...)) // setting the state here
.catch((error) => dispatch(...)) // set error state
//comma here
,[user]);
【讨论】:
我已经更新了我的问题以反映这一点。现在可以识别并调用该函数,但它不会触发钩子上的刷新。【参考方案3】:我已经使用布尔值实现了一个解决方案,但我认为必须有更好的方法来做到这一点。使用对象的公认解决方案是相似的,但我不喜欢暴露的 API 或 refresh()
或 refresh(!resfreshSomething)
的外观。
所以我想出了以下解决方案:
const useGetFetch(url, token, user, parser) =>
const [state, dispatch] = useReducer(fetchReducer, initialState)
const [shouldRefetch, refetch] = useState();
const refresh = () => refetch();
// call upon useEffect (() => ...
return [state.response, state.loading, state.error, refresh];
这样你就可以在你的钩子之外简单地使用refresh();
。
【讨论】:
以上是关于关闭模式后刷新使用自定义挂钩获取的数据的主要内容,如果未能解决你的问题,请参考以下文章
使用自定义类型的 useAppDispatch 挂钩时,获取“类型为 'AsyncThunkAction<*> 的参数不可分配给类型为'Action<any>”的参数