当前位置: 首页 > Web前端 > HTML

教你写一个React状态管理库

时间:2023-03-28 16:21:33 HTML

鑷粠ReactHooks瀹炵幇鍚庯紝Redux浣滀负鐘舵€佺鐞嗘柟妗堝氨鏍兼牸涓嶅叆浜嗐€侱anAbramov寰堟棭灏辨彁鍒颁簡鈥滀綘鍙兘涓嶉渶瑕丷edux鈥濄€傚紑鍙戜汉鍛樹笉寰椾笉缂栧啓澶ч噺鐨勨€滄ā寮忎唬鐮佲€濄€傜箒鐞愬拰閲嶅鏄紑鍙戣€呮墍涓嶆効鎰忓蹇嶇殑銆傞櫎浜哸ctions/reducers/store绛夋蹇靛鏂版墜涓嶅弸濂藉锛屾渶澶х殑缂虹偣灏辨槸瀹冨typescript绫诲瀷鐨勬敮鎸佸お宸紝杩欏湪澶у瀷椤圭洰涓槸鏃犳硶鎺ュ彈鐨勩€傞€氳繃瀵筊edux浼樼己鐐圭殑鎬荤粨锛屾垜浠彲浠ヨ嚜宸卞啓涓€涓姸鎬佺鐞嗗簱銆傛垜浠繖娆¤杈惧埌鐨勭洰鐨勶細typescript绫诲瀷瑕佽冻澶熷畬鍠勫拰绠€鍗曪紝姒傚康瑕佸皯浜嶳eactHooks銆傚洜姝わ紝闃呰鏈枃妗g殑鍓嶆彁鏄啛鎮塕eactHooks銆乼ypescript绛夛紝鏈変竴瀹氱殑姒傚康銆傚ソ鐨勶紝閭f垜浠紑濮嬪惂銆傛€濊矾鐩墠娴佽鐨勫緢澶氱姸鎬佺鐞嗗簱杩囦簬澶嶆潅锛屾贩鏉備簡寰堝姒傚康鍜孉PI锛屾垜浠渶瑕佽鍒掑浣曞疄鐜般€傜姸鎬佺鐞嗘槸鐘舵€佹敼鍠勭殑鏈€缁堜綋鐜般€傛垜浠殑鐩爣鏄娇鐢ㄥ緢灏戠殑API浣垮叾瓒冲绠€鍗曘€傛兂涓€鎯筹紝鑳戒笉鑳借€冭檻鐢–ontext鏉ョ┛閫忚繘琛岀鐞嗭紝浣跨敤鏈€鍩烘湰鐨剈seState绛塰ook鏉ュ瓨鍌ㄧ姸鎬侊紝閭e氨璇曡瘯鍚с€備笅闈㈡槸涓変釜鏈€绠€鍗曠殑鍔熻兘缁勪欢Demo锛屾垜浠敤瀹冩潵鍋氬疄楠岋細/div>;}鎰忚瘑鍒版垜浠畾涔変簡Context锛屼竴涓潪甯稿熀鏈殑鐘舵€佹ā鍨?/鎻忚堪浜咰ontext鎺ュ彛鐨勭被鍨婭StoreContext{count:number;setCount:React.Dispatch>;澧為噺锛氾紙锛?>鏃犳晥锛沝ecrement:()=>void;}//鍒涘缓涓€涓病鏈夐粯璁ゅ€肩殑涓婁笅鏂囥€備负浜嗘紨绀烘柟渚匡紝鏂█exportconstStoreContext=React.createContext(undefinedasunknownasIStoreContext);andDefinethebasicstate閰嶅悎ContextfunctionApp(){//Definethestateconst[count,setCount]=React.useState(0);constincrement=()=>setCount(count+1);const鍑忛噺=()=>setCount(count-1);//WrapProvider锛屾墍鏈夌殑瀛愮粍浠堕兘鍙互鑾峰緱涓婁笅鏂囧€煎湪CardBody涓娇鍏剁┛閫忓€煎嚱鏁癈ardBody(){//鑾峰彇澶栭儴瀹瑰櫒涓殑鐘舵€乧onststore=React.useContext(StoreContext);returnText{store.count}

;}杩欐牱锛屼竴涓渶绠€鍗曠殑绌块€忕姸鎬佺鐞嗙殑浠g爜灏卞啓濂戒簡锛屽ぇ瀹舵湁娌℃湁鍙戠幇浠€涔堥棶棰橈紵鐘舵€佺殑涓氬姟閫昏緫鍐欏湪App缁勪欢涓€傝繖娈典唬鐮佽€﹀悎搴﹀お楂樹簡锛佹⒊鐞嗕竴涓嬶紝鎴戜滑闇€瑕侀€氳繃鑷畾涔夐挬瀛愭潵鎻愬彇搴旂敤鐨勭姸鎬侊紝淇濇寔閫昏緫鍜岀粍浠剁殑绾噣銆?/浣跨敤鑷畾涔夐挬瀛愮鐞咥pp涓殑鐘舵€侊紝灏嗛€昏緫鍜岀粍浠舵€ц兘鍒嗙functionuseStore(){//瀹氫箟鐘舵€乧onst[count,setCount]=React.useState(0);constincrement=()=>setCount(count+1);const鍑忛噺=()=>setCount(count-1);return{count,setCount,increment,decrement,};}鍦ˋppApp(){conststore=useStore();涓娇鐢ㄨ繖涓挬瀛愬嚱鏁?return();}鐜板湪鏇磋垝鏈嶄簡锛岄€昏緫鍦ㄥ崟鐙殑hook涓帶鍒讹紝鍏锋湁楂樺唴鑱氱殑鐗圭偣銆傛兂鎯冲彲鑳借繕涓嶅锛寀seStore鍜孲toreContext鐨勯€昏緫涓嶅琛旀帴锛岀户缁細灏唘seStore鍜孲toreContext.Provider鍒嗙鎴愪竴涓粍浠禼onstProvider:React.FC=({children})=>{conststore=useStore();杩斿洖{children};};鍐嶇湅鐪婣pp缁勪欢锛屾槸涓嶆槸寰堟竻妤氾紵functionApp(){return();}閭d箞鎴戜滑鍙互鎶婅繖涓ā寮忓皝瑁呮垚涓€涓柟娉曪紝閫氳繃宸ュ巶妯″紡鏉ュ垱寤篊ontext鍜孭rovider銆?/閫氳繃鍙傛暟浼犻€掕嚜瀹氫箟Hook//瀹氫箟閫氱敤鎻忚堪涓婁笅鏂囧舰鐘跺鍑哄嚱鏁癱reateContainer(useHook:(initialState?:State)=>Value){constContext=React.createContext(undefinedas鏈煡鍊硷級锛沜onstProvider:React.FC<{initialState?:State}>=({initialState,children})=>{//浣跨敤澶栭儴閽╁瓙constvalue=useHook(initialState);杩斿洖{children};};return{Provider,Context};}OK锛屼竴涓畝鍗曠殑鐘舵€佺鐞嗗氨褰㈡垚浜嗐€傝鎴戜滑璇曡瘯鐪嬶紝灏嗕箣鍓嶅畾涔夌殑useStore浠g爜绉诲埌createContainer涓璭xportconstBaseStore=createContainer(()=>{//瀹氫箟鐘舵€乧onst[count,setCount]=React.useState(0);constincrement=()=>setCount(count+1);constdecrement=()=>setCount(count-1);return{count,setCount,increment,decrement,};});App涓浛鎹负BaseStore瀵煎嚭鐨凱roviderfunctionApp(){return();}鍦–ardBody涓娇鐢˙aseStore瀵煎嚭鐨凜ontext锛屽洜涓哄畾涔変腑浣跨敤浜嗘硾鍨嬶紝骞朵笖杩欓噷鍙互瀹岀編璇嗗埆褰撳墠store鐨勫舰鐘讹紝杩欐牱WitheditorsmartpromptfunctionCardBody(){conststore=React.useContext(BaseStore.Context);returnText{store.count}
;}閭d箞鎭枩浣狅紝浣犲凡缁忓垱寤轰簡涓€涓睘浜庤嚜宸辩殑鐘舵€佺鐞嗗簱銆傛垜浠皢鍏跺懡鍚嶄负unstated-nextadjustment锛屼絾鍦ㄤ究鍒╂€у拰鎬ц兘涔嬮棿鎬绘槸瀛樺湪鏉冭 銆傛鏃犵枒闂紝鎴愬姛涔熸槸Context锛屽け璐ヤ篃鏄疌ontext銆傜敱浜庡叾鍏锋湁绌块€忔€х殑涔辨洿鏂扮壒鎬э紝浼氬鑷存墍鏈塕eact.memo浼樺寲澶辨晥銆備竴涓猻etState宸偣璁╂暣涓」鐩窡鐫€rerender锛岃繖鏄瀬鍏朵笉鑳芥帴鍙楃殑銆傚洜涓鸿嚜瀹氫箟Hook姣忔鎵ц閮戒細杩斿洖涓€涓叏鏂扮殑瀵硅薄锛屾墍浠rovider姣忔閮戒細鏀跺埌杩欎釜鍏ㄦ柊鐨勫璞°€傛墍鏈変娇鐢ㄨ繖涓狢ontext鐨勫瓙缁勪欢涓€璧锋洿鏂帮紝瀵艰嚧鏃犳剰涔夌殑娴垂璋冪敤銆傛湁璁″垝鍚楋紵鎯充竴鎯筹紝鍔炴硶鎬绘槸姣斿洶闅惧銆傛垜浠彲浠ヤ紭鍖朇ontext涓婁笅鏂囩殑鐗规€э紝鏀惧純瀵艰嚧閲嶆柊娓叉煋鐨勭壒鎬э紙涔熷氨鏄瘡娆¢兘浼犵粰浠栦竴涓浐瀹氱殑寮曠敤锛夈€傝繖鏍风殑璇濓紝濡傛灉鐘舵€佹敼鍙樹簡锛屾洿鏂扮殑瀛愮粍浠舵病鏈夋洿鏂版€庝箞鍔烇紵鏈夋病鏈夊姙娉曡Е鍙戦噸鏂版覆鏌擄紵绛旀鏄痵etState锛屾垜浠彲浠ュ皢setState鏂规硶鎻愬崌鍒癈ontext涓紝璁╁鍣ㄨ皟搴﹁皟鐢ㄦ洿鏂般€?/鍦╟reateContainer鍑芥暟涓?/棣栧厛鎴戜滑鍙互璁剧疆Context涓嶈Е鍙憆ender//杩欓噷createContext鐨勭浜屼釜鍙傛暟鐨勫嚱鏁拌繑鍥炲€间负0锛岃〃绀轰笉瑙﹀彂render//娉ㄦ剰锛氳繖涓狝PI鏄潪姝e紡鐨勩€傚綋鐒朵綘涔熷彲浠ヤ娇鐢╱seRef灏嗘暣涓狢ontext鐨勫€艰繘琛岃浆鍙戯紝浣垮叾涓嶅彲鍙?/浣跨敤闈炴寮忕殑API鍙槸涓轰簡涓嶄娇鐢╮ef淇濆瓨浠g爜馃槃constContext=React.createContext(undefinedasunknownasValue,()=>0);鏃㈢劧Context鏄笉鍙彉鐨勶紝閭d箞濡備綍瀹炵幇鏇存柊閫昏緫鍛紵鎬濊矾鍙互鏄繖鏍风殑锛氭垜浠湪瀛愮粍浠舵寕杞界殑鏃跺€欑粰Context娣诲姞涓€涓洃鍚櫒锛屽嵏杞界殑鏃跺€欑Щ闄ゅ畠锛屽綋Context鏇存柊鐨勬椂鍊欒皟鐢ㄨ繖涓洃鍚櫒璁╁畠閲嶆柊娓叉煋銆傚0鏄庝竴涓狢ontext鏀惧埌listener//杩欎簺瀛愮粍浠剁殑createContainer鍑芥暟涓璫onstListenerContext=React.createContextvoid>>(newSet());鐜板湪闇€瑕佽繖鏍蜂竴涓瓙缁勪欢Hook锛屾垜鎯抽€夋嫨store涓殑涓€浜涚姸鎬佹潵浣跨敤锛屼笉闇€瑕侀€氱煡鎴戝幓鏇存柊涓嶇浉鍏崇殑鐘舵€佸彉鍖栥€傜劧鍚庢垜浠皢鍏跺懡鍚嶄负useSelector锛屽畠鐢ㄤ簬鐩戞帶鍝簺鍊肩殑鍙樺寲鍙互浣胯繖涓粍浠堕噸鏂版覆鏌撱€傚嚱鏁扮被鍨嬪彲浠ヨ繖鏍峰畾涔夛細閫氳繃浼犲叆涓€涓嚱鏁帮紝鎵嬪姩鎸囧畾瑕佺洃鍚殑鍊硷紝骞惰繑鍥炶繖涓€?/functionuseSelector(selector:(value:Value)=>Selected)鍦╟reateContainer鍑芥暟涓?Selected{}鐒跺悗鎴戜滑鏉ュ疄鐜拌繖涓猽seSelector銆傞鍏堟槸瑙﹀彂閲嶆柊娓叉煋鐨勬柟娉曘€傝繖閲屼娇鐢╮educer鏉ュ鍔犲畠鍐呴儴鐨勮嚜澧炪€傝皟鐢ㄦ椂涓嶉渶瑕佷紶閫掑弬鏁般€俢onst[,forceUpdate]=React.useReducer((c)=>c+1,0);杩欓噷鎴戜滑闇€瑕佸尮閰岰ontext閫氫俊锛屼粠鑰岃幏鍙栨墍鏈夌殑鐘舵€侊紝浼犻€掔粰selector鍑芥暟//杩欓噷鐨凜ontext涓嶅啀鍏锋湁瑙﹀彂鏇存柊鐨勭壒鎬onstvalue=React.useContext(Context);constlisteners=React.useContext(ListenerContext);//璋冪敤鏂规硶鑾峰彇selectionValueconstselected=selector(value);鍒涘缓鐩戝惉鍑芥暟锛岄€氳繃Ref杞彂锛屽皢閫変腑鐨勭姸鎬佹彁渚涚粰鐩戝惉鍑芥暟锛岃杩欎釜鍑芥暟鑾峰彇鍒版渶鏂扮殑鐘舵€侊紝constStoreValue={selector,value,selected,};constref=React.useRef(StoreValue);ref.current=StoreValue;瀹炵幇杩欎釜鐩戝惉鍣ㄥ嚱鏁癴unctionlistener(nextValue:Value){try{constrefValue=ref.current;//濡傛灉鍓嶅悗姣旇緝鐨勫€肩浉鍚岋紝鍒欎笉浼氳Е鍙憆enderif(refValue.value===nextValue){return;}//瀵归€変腑鐨勫€艰繘琛屾祬姣旇緝锛屽鏋滅浉鍚岀殑鍊间笉瑙﹀彂娓叉煋constnextSelected=refValue.selector(nextValue);//if(isShadowEqual(refValue.selected,nextSelected)){杩斿洖;}}catch(e){//ignore}//杩愯鍒拌繖閲岋紝璇存槑鍊兼敼鍙樹簡锛岃Е鍙憆enderforceUpdate();}鎴戜滑闇€瑕佸湪缁勪欢鎸傝浇/鍗歌浇鏃舵坊鍔?绉婚櫎listenerReact.useLayoutEffect(()=>{listeners.add(listener);return()=>{listeners.delete(listener);};},[]);瀹屾暣瀹炵幇濡備笅锛歠unctionuseSelector(selector:(value:Value)=>Selected):Selected{const[,forceUpdate]=React.useReducer((c)=>c+1,0);constvalue=React.useContext(涓婁笅鏂?;constlisteners=React.useContext(ListenerContext);constselected=閫夋嫨鍣紙鍊硷級锛沜onstStoreValue={閫夋嫨鍣紝鍊硷紝閫夋嫨锛寎;constref=React.useRef(StoreValue);ref.current=StoreValue;React.useLayoutEffect(()=>{functionlistener(nextValue:Value){try{constrefValue=ref.current;if(refValue.value===nextValue){return;}constnextSelected=refValue.selector(nextValue);if(isShadowEqual(refValue.selected,nextSelected)){return;}}catch(e){//蹇界暐}forceUpdate();}渚﹀惉鍣╯.add锛堢洃鍚櫒锛夛紱return()=>{listeners.delete(listener);};},[]);returnselected;}鏈変簡鏈€鍚庝竴姝ョ殑閫夋嫨鍣紝鎴戜滑鍦≒rovider//createContainer鍑芥暟涓噸鍐檆onstProvider锛歊eact.FC<{initialState?:State}>=({initialState,children})=>{constvalue=浣跨敤閽╁瓙锛堝垵濮嬬姸鎬侊級锛?/浣跨敤Ref璁╃洃鍚櫒Context娌℃湁瑙﹀彂鏇存柊鐨勮兘鍔沜onstlisteners=React.useRefvoid>>(newSet()).current;//useHook涓殑setState姣忔閮戒細鏇存柊杩欎釜缁勪欢锛岃鐩戝惉鍣ㄨЕ鍙戣皟鐢紝璁╂敼鍙樼姸鎬佺殑瀛愮粍浠舵覆鏌搇isteners.forEach((listener)=>{listener(value);});return({children});};浣犲畬鎴愪簡锛乽seSelector杩斿洖鐨勬柊瀵硅薄涓嶳eact.memo鐩告瘮浼氭瘮杈冩祬銆侫PI鐨勪娇鐢ㄤ篃鍍廟eact-Redux锛屾病鏈夊涔犳垚鏈€傜湅涓€涓嬬敤娉昮unctionCardBody(){//涓€鏃ount鍙戠敓鍙樺寲锛岃繖涓粍浠跺氨浼氳Е鍙憆erender//濡傛灉瑙夊緱楹荤儲锛屽彲浠ヤ娇鐢╨odash涓殑pick鍑芥暟conststore=BaseStore.useSelector(({count,澧為噺})=>({璁℃暟,澧為噺}));returnText{store.count}
;}鍊煎緱娉ㄦ剰鐨勬槸锛宑reateContainer鍑芥暟涓繑鍥炵殑鍊煎苟涓嶈兘姣忔閮介噸鏂扮敓鎴愩€傛垜浠慨鏀笲aseStoreexportconstBaseStore=createContainer(()=>{//瀹氫箟鐘舵€乧onst[count,setCount]=React.useState(0);//灏嗕箣鍓嶅畾涔夌殑涓や釜鍑芥暟鏇挎崲涓簎seMethods鍖咃紝淇濊瘉鑷鑷噺鍑芥暟寮曠敤鏈洿鏀圭殑甯搁噺鏂规硶=useMethods({increment(){setCount(count+1);},decrement(){setCount(count-1);},});return{count,setCount,...methods,};});杩欓噷鐨剈seMethodsHook鏄垜涔嬪墠涓€绡囨枃绔犲垎鏋愯繃鐨勶紝鐢ㄦ潵鏇夸唬useCallback鐨勩€傛湁鍏虫簮浠g爜锛岃鍙傝Heo銆傞敠涓婃坊鑺憋紝鍙互缁撳悎useSelector鍜宭odash.picker灏佽涓€涓洿甯哥敤鐨凙PI锛屽湪createContainer鍑芥暟涓懡鍚嶄负usePicker//鍑芥暟usePicker(selected:Selected[]):Pick{returnuseSelector((state)=>pick(stateasRequired,selected));}璇曡瘯鏁堟灉锛歠unctionCardBody(){conststore=BaseStore.usePicker(['count','increment']);returnText{store.count}
;}鎬荤粨涓€涓嬶紝杩欐槸鎴戝綋鏃跺啓涓€涓姸鎬佺鐞嗙殑鎬濊矾锛屼綘瀛︿細浜嗗悧锛熸簮鐮佽Heo锛岃繖涔熸槸鎴戜滑姝e湪浣跨敤鐨勭姸鎬佺鐞嗐€傝冻澶熻交閲忥紝閰嶅悎Hooks锛屽畬缇庢敮鎸乀S锛屽師浠g爜鏀归€犱笉闅俱€傚湪鐢熶骇鐜绋冲畾杩愯涓€骞村銆傛渶澶嶆潅鐨勯」鐩槸涓€娆℃€ф覆鏌?000澶氫釜閫掑綊缁撴瀯鐨勭粍浠讹紝鎬ц兘杩樻槸寰堜紭绉€鐨勩€傛杩庡ぇ瀹禨tar銆傛杩庡叧娉ㄥ井淇″叕浼楀彿鍓嶇涔嬫槦锛屽悗缁垜浠細鎶婂悇绉嶇粍浠剁殑瀹炵幇鎬濊矾鍙戠粰澶у銆?/p>