剖析的源码来自https://github.com/alibaba/ho...

useUrlState

简介

useUrlState是一个通过url query来治理state的Hook。url query,即网页url的问号前面跟着的一串属性值。该hook利用次要在以下两个方面:

  • 将组建的属性值晋升到url进行治理。
  • 利用该hook来治理url的query。

useUrlState能够做到不刷新页面即可扭转query参数,应用起来比拟不便。

useUrlState有个比拟非凡的中央在于:应用它是须要独立装置@ahooksjs/use-url-state库的,源码中它也与其余hook寄存在了不同的地位。可能是因为useUrlState须要应用react-router和query-string,因而按需下载,防止无意义的多下载几个库。

根本用法

它的用法比较简单,同useSetState相似,初始值都为对象中的键值对;应用如setState(即result的第二个参数)传入须要扭转的键值对即可,也可传入函数;不同之处在于无奈减少属性值。

简略用例

该用例来自官网文档,实现了其根本用法:将状态同步到 url query 中。而后通过设置值为 undefined,能够将属性复原为一开始传入的默认值。

import React from 'react';import useUrlState from '@ahooksjs/use-url-state';export default () => {  const [state, setState] = useUrlState({ count: '1' });  return (    <>      <button        style={{ marginRight: 8 }}        type="button"        onClick={() => setState({ count: Number(state.count || 0) + 1 })}      >        add      </button>      <button type="button" onClick={() => setState({ count: undefined })}>        clear      </button>      <div>state: {state?.count}</div>    </>  );};

源码剖析

首先是一些接口和类型的定义。

//...省略局部const rc = tmp as any;//options参数接口:export interface Options {  navigateMode?: 'push' | 'replace';//状态变更时切换 history 的形式  parseOptions?: ParseOptions;//query-string parse 的配置  stringifyOptions?: StringifyOptions;//query-string stringify 的配置}//parseOptions的默认定义const baseParseConfig: ParseOptions = {  parseNumbers: false,  parseBooleans: false,};//stringifyOptions的默认定义const baseStringifyConfig: StringifyOptions = {  skipNull: false,  skipEmptyString: false,};//定义类型UrlState为<string, any>键值对type UrlState = Record<string, any>;

对传入的参数进行了肯定的默认值合并解决,接着获取以后url的location对象,获取传入的心state值,辨别react-router的5或6版本来对新旧state值进行合并。

对步骤的具体解析写于代码中的正文局部。

const useUrlState = <S extends UrlState = UrlState>(  initialState?: S | (() => S),  options?: Options,) => {  type State = Partial<{ [key in keyof S]: any }>;  const { navigateMode = 'push', parseOptions, stringifyOptions } = options || {};  const mergedParseOptions = { ...baseParseConfig, ...parseOptions };  const mergedStringifyOptions = { ...baseStringifyConfig, ...stringifyOptions };//useLocation返回示意以后页面的location对象。location对象蕴含无关以后 URL 的信息。//上面用到的有:search、hash  const location = rc.useLocation();  // react-router v5  const history = rc.useHistory?.();  // react-router v6  const navigate = rc.useNavigate?.();//起到强制组件从新渲染的作用  const update = useUpdate();  const initialStateRef = useRef(    typeof initialState === 'function' ? (initialState as () => S)() : initialState || {},  );//当location.search扭转的时候,将url的query转换成对象//在本系列上一篇文章中曾经解释过useMemo的作用,有选择性地进行从新执行,缩小耗费。  const queryFromUrl = useMemo(    () => {    return parse(location.search, mergedParseOptions);  }, [location.search]);//当queryFromUrl扭转的时候,返回目前的query值  const targetQuery: State = useMemo(    () => ({      ...initialStateRef.current,      ...queryFromUrl,    }),    [queryFromUrl],  );//获取传入的newstate值,并且反对传入函数  const setState = (s: React.SetStateAction<State>) => {    const newQuery = typeof s === 'function' ? s(targetQuery) : s;    // 1. 如果 setState 后,search 没变动,就须要 update 来触发一次更新。    // 2. update 和 history 的更新会合并,不会造成屡次更新。    update();    if (history) {      history[navigateMode]({        hash: location.hash,        //合并新旧state,并利用stringify进行转换        search: stringify({ ...queryFromUrl, ...newQuery }, mergedStringifyOptions) || '?',      });    }    if (navigate) {      navigate(        {          hash: location.hash,          search: stringify({ ...queryFromUrl, ...newQuery }, mergedStringifyOptions) || '?',        },        {          replace: navigateMode === 'replace',        },      );    }  };  return [targetQuery, useMemoizedFn(setState)] as const;};export default useUrlState;

要点剖析

useLocation

useLocation返回示意以后页面的location对象。location对象蕴含无关以后 URL 的信息。
在该源码应用到的是hash和search信息。

  • hash:=从井号 (#) 开始的 URL(锚)。该源码中间接获取了以后url的hash值,并未扭转。
  • search:=从问号 (?) 开始的 URL(查问局部),相当于query,也就是useUrlState重点解决的局部。

useUpdate

一个能够强制组件渲染的hook,用法极其简略, const update = useUpdate();而后update();即可。

parse, stringify

来自query-string库,作用是将对象和url的query(如‘?name=abc&class=2’)这两种格局进行相互转换。

useRef

useRef 返回一个可变的 ref 对象,其.current属性被初始化为传入的参数(initialValue),能够用来保留数据,返回的ref对象在组件的整个生命周期内继续存在。在这里用它来保留传入的初始值(以便当革除某个属性的时候,能够返回该属性的初始值)

参考资料:
https://cloud.tencent.com/dev...
https://react.docschina.org/d...