繁体   English   中英

如何从需要访问 state 的 React Hooks 返回 function?

[英]How to return a function from React Hooks that need access to the state?

我正在构建一个自定义钩子来管理来自 fetch/axios/promise/whateveryouwant function 的数据,这个钩子允许我随时使用我在钩子末尾返回的更新 function 更新数据。

所以现在我的钩子中有两个状态:

const [data, setData] = useState<T>(defaultValue); // the data coming from the fetch, T is defined by the user of the hook
const [query, setQuery] = useState<Array<{ key: string; value: string }>>([]); // array of query option for the URL

I wanted to implement a dynamic way to add query string to the URL, so I used the query state to have an array of object representing what I wanted but I cannot access the value of the query inside of the update function when calling from outside. 这是钩子,我强调了重要的部分:

export default function useFetchV2<T>(
  defaultValue: T,
  getData: (queryString?: string) => Promise<T>
): {
  update: () => void;
  data: T;
  updateQueryValue: (key: string, value: string) => void; // update, data, updateQueryValue are the return value of the hook.
} {
  const [data, setData] = useState<T>(defaultValue);
  const [query, setQuery] = useState<Array<{ key: string; value: string }>>([]); // THE STATE I WANT TO ACCESS

  console.log(query, data); // Here the state is updating well and everything seems fine

  const update = useCallback((): void => {
    let queryString;

    console.log(query, data);

   // But here is the problem, query and data are both at their default value. The state inside the hooks is correct but not here.

    if (query.length > 0) { // query.length always at 0
      queryString = _.reduce(
        query,
        (acc, el) => {
          return `${acc}${el.key}=${el.value.toString()}`;
        },
        '?'
      );
      console.log(queryString);
    }
    getData(queryString).then(res => setData(res));
  }, [data, getData, query]);

  const updateQueryValue = useCallback(
    (key: string, value: string): void => {
      const index = query.findIndex(el => el.key === key);
      if (index !== -1) {
        if (!value) {
          const toto = [...query];
          _.pullAt(toto, index);
          setQuery(toto);
        } else {
          setQuery(prev =>
            prev.map(el => {
              if (el.key === key) {
                return { key, value };
              }
              return el;
            })
          );
        }
      } else {
        console.log(key, value); // everything is logging well here, good key and value
        setQuery([...query, { key, value }]); // setQuery correctly update the state
      }
      update();
    },
    [query, update]
  );

  useEffect(() => {
    update();
  }, []);

  return { update, data, updateQueryValue };
}

这可能是我导出function的方式,我仍然不习惯scope。

我从一个组件中调用了 updateQueryValue。 调用了function,改了state,但是更新function看不出区别。

代码调用setQuery然后立即调用update并期望query是更新的值,但它始终是query当前值。 实现这一点是useEffect的用例。

  } else {
    console.log(key, value); // everything is logging well here, good key and value
    setQuery([...query, { key, value }]); // setQuery correctly update the state
  }
  
  // This will *always* see the current value of `query`, not the one that
  // was just created in the `else` block above.
  update();
  1. 听起来代码应该在query update ,这正是useEffect的用途。
const updateQueryValue = useCallback(
    (key: string, value: string): void => {
      const index = query.findIndex(el => el.key === key);
      if (index !== -1) {
        if (!value) {
          const toto = [...query];
          _.pullAt(toto, index);
          setQuery(toto);
        } else {
          setQuery(prev =>
            prev.map(el => {
              if (el.key === key) {
                return { key, value };
              }
              return el;
            })
          );
        }
      } else {
        setQuery([...query, { key, value }]); // setQuery correctly update the state
      }

      // This call isn't needed, it will always "see" the old value of
      // `query`
      // update();
    },
    [query, update]
  );

  // Call `update` once when this custom hook is first called as well as
  // whenever `query` changes.
  useEffect(() => {
    update();
  }, [query]); // <-- this is new, add `query` as a dependency
  1. useCallback仅在依赖 function 的身份做出决定时才需要; 例如,如果一个组件接收到 function 作为 prop,它会检查 prop 是否发生变化以决定是否重新渲染。 在这种情况下update不需要useCallback并且可能会使这个钩子更难调试。
function update() {
    let queryString;
    if (query.length > 0) { // query.length always at 0
      queryString = _.reduce(
        query,
        (acc, el) => {
          return `${acc}${el.key}=${el.value.toString()}`;
        },
        '?'
      );
      console.log(queryString);
    }
    getData(queryString).then(res => setData(res));
  });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM