剖析的源码来自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...