react hooks个人笔记-useUrlQueryState state映射查询参数

1,565 阅读1分钟

业务中在列表页,经常会出现一种情况,列表的请求参数需要和url参数对应,基于这个需求,可以设计一个 hook 将查询参数和 state 双向同步;

思路

function useUrlQueryState(initState = {}) {
  // url 参数同步到 state
  const matchUrlToState = state => nextState;

  // state 同步到 url 参数
  const matchStateToUrl = state => nextState;

  // url state: 保持 state 和 url 同步
  const [urlState, setUrlState] = useState(matchUrlToState(initState));

  // 同步 url 和 state
  const combineUrlState = useCallback((state) => {
    setUrlState(matchStateToUrl(state));
  }, []);

  // 
  return [urlState, combineUrlState];
}

matchUrlToState 和 matchStateToUrl

总体同步原则是匹配 state 和 url search params,如果能够匹配上,则需要同步:

  • matchUrlToState 初始化的时候,为惰性匹配,将 url 参数同步到 state 中;
  • matchStateToUrl 主动设置为积极匹配,将 state 匹配到 url 参数中;
function useUrlQueryState(initState = {}) {
  // 设置地址栏
  const combineUrl = url => window.history.pushState(null, null, url.toString());

  // url 参数同步到 state
  const matchUrlToState = state => {
    const url = new URL(window.location.href);
    const nextState = Object.keys(state).reduce((nextState, key) => {
      if (url.searchParams.has(key) && url.searchParams.get(key)) {
        return { ...nextState, [key]: url.searchParams.get(key) };
      } else {
        url.searchParams.set(key, state[key]);
        return { ...nextState };
      }
    }, state);
    combineUrl(url);
    return nextState;
  }

  // state 同步到 url 参数
  const matchStateToUrl = useCallback(state => {
    const url = new URL(window.location.href);
    Object.keys(state).forEach(key => {
      url.searchParams.set(key, state[key]);
    });
    combineUrl(url);
    return state;
  }, []);

  // url state: 保持 state 和 url 同步
  const [urlState, setUrlState] = useState(matchUrlToState(initState));

  // 同步 url 和 state
  const combineUrlState = useCallback((state) => {
    setUrlState(matchStateToUrl(state));
  }, [matchStateToUrl]);

  return [urlState, combineUrlState];
}