关闭模式后刷新使用自定义挂钩获取的数据

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();

【讨论】:

以上是关于关闭模式后刷新使用自定义挂钩获取的数据的主要内容,如果未能解决你的问题,请参考以下文章

php 自定义挂钩,用于排序时刷新

如何仅在 React 自定义挂钩中获取数据一次?

自定义挂钩内的 setState 调用未更新状态

如何在自定义挂钩上使用 useCallback?

使用自定义适配器刷新可见 ListView

使用自定义类型的 useAppDispatch 挂钩时,获取“类型为 'AsyncThunkAction<*> 的参数不可分配给类型为'Action<any>”的参数