关闭模态后,使用自定义钩子刷新获取的数据

时间:2020-06-24 12:04:13

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

我正在使用挂钩在我的应用程序中获取数据。钩子看起来像这样:

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]
}

具体来说,我在表单组件内部使用此钩子,以获取一些数据以用作select元素内的选项。

但是,我需要能够让用户即时添加新选项。为方便起见,我在select元素旁边创建了一个按钮。如果用户按下此按钮,将弹出一个模态,并显示另一种形式,可以创建一个新选项。这个新选项通过发布请求发送到服务器,如果成功,则模式关闭。

我面临的问题是,模式关闭后,除非刷新页面,否则无法更新使用自定义数据获取挂钩获取的初始数据。有没有一种方法可以使这种情况在不触发页面刷新的情况下发生?

我最初的直觉是使用回调函数并将其传递到useGetFetch并将其绑定到useEffect钩子。然后,我可以将其传递给模式中的表单,并在成功提交后调用该函数,但这没有用。

我正在寻找的另一个选项是useCallback钩子,但是我目前对它的了解还不够,无法知道它是否会有所帮助。

编辑

具体地说,我所做的是在父组件外部创建一个触发函数:

const trigger = () => console.log("click")

将其绑定到提取钩子上

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内调用触发器会在useEffect内触发useGetFetch,但似乎不起作用。

2 个答案:

答案 0 :(得分:2)

如果清楚地理解了您的问题,我认为您要尝试的是在用户关闭模态时强制重新引用。

您可以通过触发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>
  );
};

答案 1 :(得分:0)

我认为您在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]);