React Hooks之usePolymerAction抽象代码结构设计理念

目录
  • 背景
  • 设计理念
    • 抽象代码结构
    • 声明与定义
  • 用法
  • 高级用法
    • 拆分/合并action
  • API
    • useSetState
    • getAction
    • polymerAction
    • usePolymerActionState
    • mergePolymerAction

背景

随着React Hooks 普及起来,组件逻辑写法变成函数式;逻辑函数声明、函数代码结构,随着逻辑增加复杂,代码组织混乱,函数声明散乱;

最关键的一点,每个人对代码理解不一样,有的喜欢在一个function 写大段逻辑,有的喜欢拆分逻辑很细,

就会使在项目维护时,代码风格、代码结构,越来越不统一,难以维护。

针对上述情况,需要可以组织代码结、梳理逻辑的方法,从而达到项目维护性高、代码结构统一、逻辑清晰

设计理念

抽象代码结构

在编写代码的过程中,发现可以抽象出公共代码结构;

  • 声明可变数据/共享变量声明、state 声明/let xxx= xxx/useState
  • 方法声明/function xx () {} /action/dispatch
  • 方法调用 / xx() / action()/dispatch()

通过上图,可以把常见组件内部逻辑,分成3个部分,其中3、4属于相同部分:

:主要是声明数据,有useState/let xxx = 11;

:声明函数、方法,会涉及修改数据**setcounts**、使用数据**sendLogcount**;

其中修改与使用里会有一些辅助方法fetch来执行对应逻辑;

调用方法,3与4部分都在视图中使用函数与方法,统一称为调用方法。

把代码结构拆分、分析之后;其实在日常的开发过程中大部分代码复杂逻辑都在1与2部分,而2部分里有相互调用的逻辑,各种辅助函数相互杂糅在一起,慢慢的使得代码越来越复杂,难以阅读。

声明与定义

我们可以把1与2部分复杂封装起来,定义好规范干净的结构如

根据上图可知,把原先1、2、3 部分统一封装在一个hooks.js文件里;

  • 原先1与2部分代码通过调用**polymerAction**给聚合起来,把state与actions/方法声明给放在一起;再通过**const [state, actions, shareVars] = usePolymerActionState(countActions)**对外暴露数据与acions/方法。
  • 原先3部分封装hooks使用**usePolymerActionState**暴露方法调用,走正常调用逻辑。
  • 在视图里,正常使用hooks 封装方法,**return**出**usePolymerActionState**暴露数据与方法,正常调用逻辑。

可以看出核心部分,就是把state与action封装在一起高内聚,通过对象组织代码结构,而对象可以进行组合方式,来组织更大复杂的代码逻辑与结构。

从视图上来看,只调用暴露出来的方法。

总结一下,按照上述方式,可以提高项目可维护性,代码结构统一。

用法

/** @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('参入数据了');
 }}>
   <Text>{count}</Text>
</View>
 );
}

initHooksAction可以拿到数据、方法;走正常逻辑;

const countActions = polymerAction({
  count: 0
}, {
  setCounts({state, setState}, params) {
    setState({
      count: ++state.count
    })
    console.log(params)
  },
  fetch({state, setState}, count) {
    console.log(`接口请求埋点${
      count}`)
  },
  sendLog({state, setState, actions}, count) {
    actions.fetch(count)
    console.log(`发送相关埋点${
      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:底层会重写actions方法,shareVar数据,

返回数据是对应polymerAction里声明的数据、方法

initHooksAction:封装hooks 逻辑

高级用法

拆分/合并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**可以把多个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

参数 说明 类型 默认值
stateObj 必传,声明state object {}
actionObj 必传,声明方法、函数 object {}
shareValObj 可选项,传入默认的状态值 boolean {}

Result

参数 说明 类型
state 状态值 object
actions 操作集合 Actions
shareVal 共享变量 object

actionObj

const handleAction = polymerAction({},{
  /**
   *  刷新接口
   */
  onRefreshList({ state, actions,shareVars,setState,setShareVars },param) {
  ...
  },
     /**
   *  接口报错,刷新接口
   */
  onRefreshListError({ state, setState, shareVars, actions }) {
    actions.getList(true);
  },
},{});
参数 说明 类型
state 获取 stateObj **object**
actions 获取 actionObj **object**
shareVars 获取 shareValObj **object**
setState 设置 state **({}) => void**
setShareVars 设置 shareVal **({}) => void**

usePolymerActionState

根据传入action,转换成能改变页面的**PolymerActionState**

function initEffect(param) {
  const [state, actions] = usePolymerActionState(scrollListAction);
  ...
  ...
  return [state, action]
}
const [state, actions,shareVal] = usePolymerActionState(polymerAction);

Params

参数 说明 类型
polymerAction 必传,声明polymerActionState 集合 **Array**

Result

参数 说明 类型
state 状态值 **object**
actions 操作集合 **object**
shareVal 共享变量 **object**

mergePolymerAction

合并多个 **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 关联
function usePolymerActionState(param) {
  const [state, action = {}, shareVar = {}] = param;
  const actions = action;
  // Object.assign({}, xxx) 多个加载重复组件生成对应数据,防止数据相互覆盖情况
  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(`请在模块中的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抽象代码结构设计理念的详细内容,更多关于React Hooks usePolymerAction的资料请关注我们其它相关文章!

(0)

相关推荐

  • Jetpack Compose对比React Hooks API相似度

    目录 React Component vs Composable JSX vs DSL loop If statement key component Children Prop vs Children Composable Context vs Ambient(CompositionLocal) createContext : ambientOf Provider : Provider useContext : Ambient.current useState vs State useMemo

  • ahooks解决React闭包问题方法示例

    引言 本文是深入浅出 ahooks 源码系列文章的第三篇,这个系列的目标主要有以下几点: 加深对 React hooks 的理解. 学习如何抽象自定义 hooks.构建属于自己的 React hooks 工具库. 培养阅读学习源码的习惯,工具库是一个对源码阅读不错的选择. 注:本系列对 ahooks 的源码解析是基于 v3.3.13.自己 folk 了一份源码,主要是对源码做了一些解读,可见 详情. 系列文章: 大家都能看得懂的源码 ahooks 整体架构篇 如何使用插件化机制优雅的封装你的请求

  • react hooks闭包陷阱切入浅谈

    目录 引言 1.一个熟悉的闭包场景 2 浅谈hooks原理,理解useEffect 的 “闭包陷阱” 出现原因 2 难道真的要在依赖数组里写上的值,才能拿到新鲜的值? 3 为什么使用useRef能够每次拿到新鲜的值? 4 完毕 引言 首先,本文并不会讲解 hooks 的基本用法, 本文从 一个hooks中 “奇怪”(其实符合逻辑) 的 “闭包陷阱” 的场景切入,试图讲清楚其背后的因果.同时,在许多 react hooks 奇技淫巧的文章里,也能看到 useRef 的身影,那么为什么使用 useR

  • React函数组件useContext useReducer自定义hooks

    目录 一.hooks(useContext) 二.hooks(useReducer) 三.hooks(useContext搭配useReducer使用) 四.自定义hooks 一.hooks(useContext) 接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值.当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定. 新建useContext.js

  • 进入Hooks时代写出高质量react及vue组件详解

    目录 概述 1.组件什么时候拆?怎么拆? 2.如何组织拆分出的组件文件? 3.如何用hooks抽离组件逻辑? 题外话:全局状态的管理 概述 vue和react都已经全面进入了hooks时代(在vue中也称为组合式api,为了方便后面统一称为hooks),然而受到以前react中类组件和vue2写法的影响,很多开发者都不能及时转换过来,以致于开发出一堆面条式代码,整体的代码质量反而不如改版以前了. hooks组件到底应该如何写,我也曾为此迷惘过一段时间.特别我以前以react开发居多,但在转到新岗

  • ahooks正式发布React Hooks工具库

    目录 起因 解法 共建 项目目标 品牌升级 社区开源 API 规范 示例演示 开发迭代 下一步 起因 从 React Hooks 正式发布到现在,越来越多的项目正在使用 Function Component 替代 Class Component,Hooks 这一新特性也逐渐被广泛的使用. 然而在实践的过程中,我们发现在很多常见的场景下,大部分逻辑是重复且可被复用的,如对数据请求的逻辑处理,对防抖节流的逻辑处理等,同样的代码经常会在同一个或不同的项目中被重复的编写 . 另一方面,由于 Hooks

  • React Hooks之usePolymerAction抽象代码结构设计理念

    目录 背景 设计理念 抽象代码结构 声明与定义 用法 高级用法 拆分/合并action API useSetState getAction polymerAction usePolymerActionState mergePolymerAction 背景 随着React Hooks 普及起来,组件逻辑写法变成函数式:逻辑函数声明.函数代码结构,随着逻辑增加复杂,代码组织混乱,函数声明散乱: 最关键的一点,每个人对代码理解不一样,有的喜欢在一个function 写大段逻辑,有的喜欢拆分逻辑很细,

  • React hooks的优缺点详解

    前言 Hook 是 React 16.8 的新增特性.它是完全可选的,并且100%向后兼容.它可以让你使用函数组件的方式,运用类组件以及 react 其他的一些特性,比如管理状态.生命周期钩子等.从概念上讲,React 组件一直更像是函数.而 Hook 则拥抱了函数,同时也没有牺牲 React 的精神原则. 优点: 1.代码可读性更强,原本同一块功能的代码逻辑被拆分在了不同的生命周期函数中,容易使开发者不利于维护和迭代,通过 React Hooks 可以将功能代码聚合,方便阅读维护.例如,每个生

  • React Hooks常用场景的使用(小结)

    前言 React 在 v16.8 的版本中推出了 React Hooks 新特性.在我看来,使用 React Hooks 相比于从前的类组件有以下几点好处: 代码可读性更强,原本同一块功能的代码逻辑被拆分在了不同的生命周期函数中,容易使开发者不利于维护和迭代,通过 React Hooks 可以将功能代码聚合,方便阅读维护: 组件树层级变浅,在原本的代码中,我们经常使用 HOC/render props 等方式来复用组件的状态,增强功能等,无疑增加了组件树层数及渲染,而在 React Hooks

  • 基于react hooks,zarm组件库配置开发h5表单页面的实例代码

    最近使用React Hooks结合zarm组件库,基于js对象配置方式开发了大量的h5表单页面.大家都知道h5表单功能无非就是表单数据的收集,验证,提交,回显编辑,通常排列方式也是自上向下一行一列的方式显示 , 所以一开始就考虑封装一个配置化的页面生成方案,目前已经有多个项目基于此方式配置开发上线,思路和实现分享一下. 使用场景 任意包含表单的h5页面(使用zarm库,或自行适配自己的库) 目标 代码实现简单和简洁 基于配置 新手上手快,无学习成本 老手易扩展和维护 写之前参考了市面上的一些方案

  • 记录一次完整的react hooks实践

    写在前面 React在16.8版本正式发布了Hooks.关注了很久,最近正好有一个小需求,赶紧来试一下. 需求描述 需求很简单,部门内部的一个数据查询小工具.大致长成下面这样: 用户首次访问页面,会拉取数据展示.输入筛选条件,点击查询后,会再次拉取数据在前端展示. 需求实现 使用React Class Component的写法 如果使用以前的class写法,简单写一下,代码可能大概长成下面这样: import React from 'react'; import { Tabs, Input, R

  • react hooks实现原理解析

    目录 react hooks 实现 Hooks 解决了什么问题 Hooks API 类型 首先接触到的是 State hooks 其次接触到的是 Effect hooks 最后接触到的是 custom hooks Hooks 实现方式 问题一:useState dispatch 函数如何与其使用的 Function Component 进行绑定 react hooks 实现 Hooks 解决了什么问题 在 React 的设计哲学中,简单的来说可以用下面这条公式来表示: UI = f(data)

  • 30分钟精通React今年最劲爆的新特性——React Hooks

    你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? --拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function. 你还在为搞不清使用哪个生命周期钩子函数而日夜难眠吗? --拥有了Hooks,生命周期钩子函数可以先丢一边了. 你在还在为组件中的this指向而晕头转向吗? --既然Class都丢掉了,哪里还有this?你的人生第一次不再需要面对this. 这样看来,说React Hooks是今年最劲爆的新特性真的毫不夸张.如果你也对react

  • React Hooks的深入理解与使用

    你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? --拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function. 你还在为搞不清使用哪个生命周期钩子函数而日夜难眠吗? --拥有了Hooks,生命周期钩子函数可以先丢一边了. 你在还在为组件中的this指向而晕头转向吗? --既然Class都丢掉了,哪里还有this?你的人生第一次不再需要面对this. 这样看来,说React Hooks是今年最劲爆的新特性真的毫不夸张.如果你也对react

  • 详解如何使用React Hooks请求数据并渲染

    前言 在日常的开发中,从服务器端异步获取数据并渲染是相当高频的操作.在以往使用React Class组件的时候,这种操作我们已经很熟悉了,即在Class组件的componentDidMount中通过ajax来获取数据并setState,触发组件更新. 随着Hook的到来,我们可以在一些场景中使用Hook的写法来替代Class的写法.但是Hook中没有setState.componentDidMount等函数,又如何做到从服务器端异步获取数据并渲染呢?本文将会介绍如何使用React的新特性Hook

  • 详解如何构建自己的react hooks

    1. 常用的一个 hooks 官方中提供了几个内置的钩子,我们简单了解下他们的用法. 1.1 useState: 状态钩子 需要更新页面状态的数据,我们可以把他放到 useState 的钩子里.例如点击按钮一下,数据加 1 的操作: const [count, setCount] = useState(0); return (<> <p>{ count}</p> <button onClick = { () => setCount(count + 1) }&

随机推荐