【问题标题】: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,但它似乎不会那样工作。

【问题讨论】:

  • 好吧,据我了解,问题是您想在用户关闭模式时重新获取数据?我说的对吗?
  • 是的,你是对的。

标签: javascript reactjs react-hooks fetch use-effect


【解决方案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();

【讨论】:

    猜你喜欢
    • 2020-06-20
    • 1970-01-01
    • 2021-10-26
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    • 2017-05-26
    相关资源
    最近更新 更多