React?Hooks之usePolymerAction抽象代碼結(jié)構(gòu)設(shè)計(jì)理念
背景
隨著React Hooks 普及起來,組件邏輯寫法變成函數(shù)式;邏輯函數(shù)聲明、函數(shù)代碼結(jié)構(gòu),隨著邏輯增加復(fù)雜,代碼組織混亂,函數(shù)聲明散亂;
最關(guān)鍵的一點(diǎn),每個(gè)人對(duì)代碼理解不一樣,有的喜歡在一個(gè)function 寫大段邏輯,有的喜歡拆分邏輯很細(xì),
就會(huì)使在項(xiàng)目維護(hù)時(shí),代碼風(fēng)格、代碼結(jié)構(gòu),越來越不統(tǒng)一,難以維護(hù)。
針對(duì)上述情況,需要可以組織代碼結(jié)、梳理邏輯的方法,從而達(dá)到項(xiàng)目維護(hù)性高、代碼結(jié)構(gòu)統(tǒng)一、邏輯清晰
設(shè)計(jì)理念
抽象代碼結(jié)構(gòu)
在編寫代碼的過程中,發(fā)現(xiàn)可以抽象出公共代碼結(jié)構(gòu);
- 聲明可變數(shù)據(jù)/共享變量聲明、state 聲明/let xxx= xxx/useState
- 方法聲明/function xx () {} /action/dispatch
- 方法調(diào)用 / xx() / action()/dispatch()
通過上圖,可以把常見組件內(nèi)部邏輯,分成3個(gè)部分,其中3、4屬于相同部分:
:主要是聲明數(shù)據(jù),有useState/let xxx = 11;
:聲明函數(shù)、方法,會(huì)涉及修改數(shù)據(jù)**setcounts**、使用數(shù)據(jù)**sendLogcount**;
其中修改與使用里會(huì)有一些輔助方法fetch來執(zhí)行對(duì)應(yīng)邏輯;
調(diào)用方法,3與4部分都在視圖中使用函數(shù)與方法,統(tǒng)一稱為調(diào)用方法。
把代碼結(jié)構(gòu)拆分、分析之后;其實(shí)在日常的開發(fā)過程中大部分代碼復(fù)雜邏輯都在1與2部分,而2部分里有相互調(diào)用的邏輯,各種輔助函數(shù)相互雜糅在一起,慢慢的使得代碼越來越復(fù)雜,難以閱讀。
聲明與定義
我們可以把1與2部分復(fù)雜封裝起來,定義好規(guī)范干凈的結(jié)構(gòu)如
根據(jù)上圖可知,把原先1、2、3 部分統(tǒng)一封裝在一個(gè)hooks.js文件里;
- 原先1與2部分代碼通過調(diào)用**polymerAction**給聚合起來,把state與actions/方法聲明給放在一起;再通過**const [state, actions, shareVars] = usePolymerActionState(countActions)**對(duì)外暴露數(shù)據(jù)與acions/方法。
- 原先3部分封裝hooks使用**usePolymerActionState**暴露方法調(diào)用,走正常調(diào)用邏輯。
- 在視圖里,正常使用hooks 封裝方法,**return**出**usePolymerActionState**暴露數(shù)據(jù)與方法,正常調(diào)用邏輯。
可以看出核心部分,就是把state與action封裝在一起高內(nèi)聚,通過對(duì)象組織代碼結(jié)構(gòu),而對(duì)象可以進(jìn)行組合方式,來組織更大復(fù)雜的代碼邏輯與結(jié)構(gòu)。
從視圖上來看,只調(diào)用暴露出來的方法。
總結(jié)一下,按照上述方式,可以提高項(xiàng)目可維護(hù)性,代碼結(jié)構(gòu)統(tǒng)一。
用法
/** @jsx createElement */ import { createElement, useEffect, useState, useRef, useMemo } from 'react'; \ export default function Realtimetrendinghotels(props) { const { gdc, mds, pageUtils } = props; return (<CustomComponent />); }
import { createElement, useEffect, useState, useRef, useMemo } from 'react';` import {initHooksAction} from './hooks'; function CustomComponent(props) { const [ count, {setCounts, sendLog} ] = initHooksAction(); return ( <View style={{width: 100, height: 100, backgroundColor: 'red'}} onClick={() => { setCounts('參入數(shù)據(jù)了'); }}> <Text>{count}</Text> </View> ); }
initHooksAction可以拿到數(shù)據(jù)、方法;走正常邏輯;
const countActions = polymerAction({ count: 0 }, { setCounts({state, setState}, params) { setState({ count: ++state.count }) console.log(params) }, fetch({state, setState}, count) { console.log(`接口請(qǐng)求埋點(diǎn)${ count}`) }, sendLog({state, setState, actions}, count) { actions.fetch(count) console.log(`發(fā)送相關(guān)埋點(diǎn)${ count}`) }, }, {}); function initHooksAction() { const [state, actions, shareVars] = usePolymerActionState(countActions); useEffect(() => { sendLog(state.count); }, [state.count]) return [state.count, actions, shareVars] }
polymerAction:聲明state、actions、shareVar;
usePolymerActionState:底層會(huì)重寫actions方法,shareVar數(shù)據(jù),
返回?cái)?shù)據(jù)是對(duì)應(yīng)polymerAction里聲明的數(shù)據(jù)、方法
initHooksAction:封裝hooks 邏輯
高級(jí)用法
拆分/合并action
const infiniteScrollAction = polymerAction({ isLoadingShow: false, isLoadingError: false, isEmptyData: false, }, { showLoading({ state, setState, shareVars, actions }) { setState({ isLoadingShow: true, isLoadingError: false, isEmptyData: false }); }, closeLoading({ state, setState, shareVars, actions }) { setState({ isLoadingShow: false }); shareVars.throttleTarget = true; }, ..., }, { throttleTarget: true, }); const handleAction = polymerAction({},{ /** * 刷新接口 */ onRefreshList({ state, setState, shareVars, actions }) { .... }, },{}) const scrollListAction = polymerAction({ cityList: [], recommendList: [], isCityListShow: false, }, { initListParam({ state, setState, shareVars, actions }) { shareVars.pageNo = 0; shareVars.dataVersion = 0; }, exp({ state, setState, shareVars, actions }, data) { const {cityName, cityCode} = shareVars.cityData; let shidsArr = []; if (data[0] && data[0].hotHotelList) { shidsArr = hotCityListShids(data); sendUT.exp(cityName, shidsArr[0].join('/'), shidsArr[1].join('/')); } else { shidsArr = shids(data); sendUT.exp(cityName, '', shidsArr.join('/')); } }, ..., }, { pageNo: 0, dataVersion: 0, cityData: { cityName: '', cityCode: '', } }); function initEffect(param) { const [state, action] = usePolymerActionState(mergePolymerAction(scrollListAction,infiniteScrollAction,handleAction)); ... ... return [state, action] }
通過**mergePolymerAction**可以把多個(gè)action,scrollListAction、infiniteScrollAction 、handleAction合并;這樣就可以任意拆分action。
API
useSetState
管理 object 類型 state 的 Hooks,用法與 class 組件的 this.setState 基本一致。
const [state,setState] = useSetState({ hehe:1, aaa:1 }); // 修改 setState({ aaa:2 })
getAction
從polymerAction里,獲取actions
const handleAction = polymerAction({},{ /** * 刷新接口 */ onRefreshList({ state, setState, shareVars, actions }) { .... }, },{}); const handle = getAction(handleAction); console.log(handle); ,{ /** * 刷新接口 */ onRefreshList({ state, setState, shareVars, actions }) { .... }, }
polymerAction
生成action 集合
const scrollListAction = polymerAction({ cityList: [], recommendList: [], isCityListShow: false, }, { initListParam({ state, setState, shareVars, actions }) { shareVars.pageNo = 0; shareVars.dataVersion = 0; }, ..., }, { pageNo: 0, dataVersion: 0, cityData: { cityName: '', cityCode: '', } });
const [state,actions,shareVal] = polymerAction(stateObj,actionObj,shareValObj)
Params
參數(shù) | 說明 | 類型 | 默認(rèn)值 |
---|---|---|---|
stateObj | 必傳,聲明state | object | {} |
actionObj | 必傳,聲明方法、函數(shù) | object | {} |
shareValObj | 可選項(xiàng),傳入默認(rèn)的狀態(tài)值 | boolean | {} |
Result
參數(shù) | 說明 | 類型 |
---|---|---|
state | 狀態(tài)值 | object |
actions | 操作集合 | Actions |
shareVal | 共享變量 | object |
actionObj
const handleAction = polymerAction({},{ /** * 刷新接口 */ onRefreshList({ state, actions,shareVars,setState,setShareVars },param) { ... }, /** * 接口報(bào)錯(cuò),刷新接口 */ onRefreshListError({ state, setState, shareVars, actions }) { actions.getList(true); }, },{});
參數(shù) | 說明 | 類型 |
---|---|---|
state | 獲取 stateObj | **object** |
actions | 獲取 actionObj | **object** |
shareVars | 獲取 shareValObj | **object** |
setState | 設(shè)置 state | **({}) => void** |
setShareVars | 設(shè)置 shareVal | **({}) => void** |
usePolymerActionState
根據(jù)傳入action,轉(zhuǎn)換成能改變頁面的**PolymerActionState**
function initEffect(param) { const [state, actions] = usePolymerActionState(scrollListAction); ... ... return [state, action] }
const [state, actions,shareVal] = usePolymerActionState(polymerAction);
Params
參數(shù) | 說明 | 類型 |
---|---|---|
polymerAction | 必傳,聲明polymerActionState 集合 | **Array** |
Result
參數(shù) | 說明 | 類型 |
---|---|---|
state | 狀態(tài)值 | **object** |
actions | 操作集合 | **object** |
shareVal | 共享變量 | **object** |
mergePolymerAction
合并多個(gè) **polymerAction**
mergePolymerAction(scrollListAction,infiniteScrollAction,handleAction)
代碼
let useState = null; let useRef = null; let useMemo = null; function useSetState(initData) { const [state, setState] = useState(initData); const dispatch = (next) => { if ( typeof next === 'object' ) { setState((pre) => Object.assign({}, pre, next)); } else { setState(next); } }; return [state, dispatch]; } function polymerAction(state, action = {}, shareVar = {}) { return [state, action, shareVar]; } function newActionData(actions, states, shareVars, setState) { let newAction = {}; Object.keys(actions) .forEach((name) => { const old = actions[name]; if ( typeof old === 'function' ) { // 重新寫actions 方法 newAction[name] = function(...arg) { return old.call(null, { state: states, shareVars, actions: newAction, setState(param, fn = () => {}) { setState(param); fn(param); }, setShareVars(param) { shareVars = Object.assign(shareVars, param); }, }, ...arg); }; } }); return newAction; } // 與hooks 關(guān)聯(lián) function usePolymerActionState(param) { const [state, action = {}, shareVar = {}] = param; const actions = action; // Object.assign({}, xxx) 多個(gè)加載重復(fù)組件生成對(duì)應(yīng)數(shù)據(jù),防止數(shù)據(jù)相互覆蓋情況 const [states, setState] = useSetState(Object.assign({}, state)); // 生成新共享變量 const shareVars = useMemo(() => (Object.assign({}, shareVar)), []) ; shareVars.updateAfterState = states; const newAction = useMemo(() => (newActionData(actions, states, shareVars, setState)), [action, states, shareVars]) return [states, newAction, shareVars]; } function getAction(polymer) { return polymer[1]; } function mergePolymerAction(action1, ...res) { const actions = action1.map(function (val, index) { let resAction = {}; res.forEach((action) => { Object.assign(resAction, action[index]); }); return Object.assign({}, val, resAction); }); return actions; } function injectState(newUseState, newUseRef, newUseMemo) { if (!newUseState || !newUseMemo) { console.warn(`請(qǐng)?jiān)谀K中的moduleInit傳入useState、useMemo, 如: moduleInit({ gdc,mds,pageUtils}) (useState, useEffect, useRef, useMemo);`); return } useState = newUseState; useRef = newUseRef; useMemo = newUseMemo; } export { useSetState, getAction, polymerAction, usePolymerActionState, mergePolymerAction, injectState };
github https://github.com/NoahsDante...
以上就是React Hooks之usePolymerAction抽象代碼結(jié)構(gòu)設(shè)計(jì)理念的詳細(xì)內(nèi)容,更多關(guān)于React Hooks usePolymerAction的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
如何將你的AngularJS1.x應(yīng)用遷移至React的方法
本篇文章主要介紹了如何將你的AngularJS1.x應(yīng)用遷移至React的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-02-02阿里低代碼框架lowcode-engine設(shè)置默認(rèn)容器詳解
這篇文章主要為大家介紹了阿里低代碼框架lowcode-engine設(shè)置默認(rèn)容器詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02React報(bào)錯(cuò)之組件不能作為JSX組件使用的解決方法
本文主要介紹了React報(bào)錯(cuò)之組件不能作為JSX組件使用的解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07使用React?Hooks模擬生命周期的實(shí)現(xiàn)方法
這篇文章主要介紹了使用React?Hooks模擬生命周期,本文舉例說明如何使用 hooks 來模擬比較常見的 class 組件生命周期,需要的朋友可以參考下2023-02-02