我有一个可以读取和写入 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 应该被触发并且应该从钩子返回新值。但由于某种原因这不会发生)