用于跟踪 history.location.search 的 useMemo 在测试环境中未触发

时间:2021-05-26 16:49:39

标签: reactjs react-router react-hooks react-testing-library

我有一个可以读取和写入 url 的钩子。它添加和读取查询参数。 这是它的样子

// usage
const [filtersValues, setFiltersValues] = useURLState(mergedInitialValues);

// the hook itself
export const useURLState = (initialState: any) => {
  const history = useHistory();

   const stringifyQuery = (queryAsObject: Record<string, any>) => {
    const { date, ...rest } = queryAsObject;
    
    const queryToStringify = ...rest;
    return queryString.stringify(queryToStringify, ARRAY_FORMAT);
  };

  const parseQueryString = useCallback((queryParams: string) => {
    const parsed = queryString.parse(queryParams, ARRAY_FORMAT);
   
    return parsed;
  }, []);

  const addQueryParamsToUrl = useCallback(
    (newQueryAsObject: Record<string, any>) => {
      const newQuery = stringifyQuery(newQueryAsObject);
      const currentQuery: string = history.location.search.slice(1); // remove leading ? in current location

      // prevent infinite loop
      if (currentQuery !== newQuery) {
        history.push({ search: newQuery });
      }
    },
    [history]
  );

  useMemo(() => {
    const mergedQueryParams = {
      ...initialState,
      ...parseQueryString(history.location.search)
    };

    addQueryParamsToUrl(mergedQueryParams);
  }, [addQueryParamsToUrl, initialState, history.location.search, parseQueryString]);

  const setFiltersState = useCallback(
    value => {
      addQueryParamsToUrl(value);
    },
    [addQueryParamsToUrl]
  );

// NOTE THIS USE MEMO
// it just parses search string and returns values as object for convenience
// used this way so url is the only source of data

  const filtersAsPlainObject = useMemo(() => {
    // query-string will not make single value an array
    // e.g. ?foo=bar will never be parsed as foo = ['bar']
    // therefore need to ensure it with this helper
    const parsed = parseQueryString(history.location.search);
    const result: Record<string, any> = getTypeSafeValues(initialState, parsed);

    return merge(cloneDeep(initialState), withDateFiltersHandled);
  }, [parseQueryString, initialState, history.location.search]);

  return [filtersAsPlainObject, setFiltersState];
}

当我在浏览器中测试它时,它工作正常,并且返回 filtersAsPlainObject 的 useMemo 总是获取最新值; 但是,当我尝试使用 react-testing-library 和 jest 对其进行测试时,问题就出现了。

只要我尝试以任何方式更新任何过滤器(例如,将它们全部清除)。 history.location.search 已更新。我在测试中可以清楚地看到它。

例如 清洁前

?grade=gradeK,grade1&location=zoom&type=camp,course

之后

'' // just empty string

但对我来说真正奇怪的是,useMemo 没有被触发,也没有收到新值。因此返回先前的值。知道我在这里做错了什么吗? (这对我来说很明显,当 history.location.search 更改时 useMemo 应该被触发并且应该从钩子返回新值。但由于某种原因这不会发生)

0 个答案:

没有答案
相关问题