IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 2-2-9 & 10 & 11 React Hooks 封装公共行为 -> 正文阅读

[JavaScript知识库]2-2-9 & 10 & 11 React Hooks 封装公共行为

- 渲染函数的输入是属性

- 输出是JSX

- 行为是Hooks

那么对于多个组件公共行为(副作用)应该如何封装呢?

公共Scroll事件的封装

可以通过Hooks封装公共的行为,例如滑动、触摸等复杂的事件处理,可以用hooks封装,从而简化使用。

import { UIEventHandler, useEffect, useRef } from "react"

class ScrollDescriptor {
  private left: number = 0
  private top: number = 0
  private scrollHeight: number = 0
  private offsetHeight: number = 0
  
  private scrollToBottomHandlers : Function[] = []
    
  public onScrollToBottom(handler : Function){
      this.scrollToBottomHandlers.push(handler)
      return () => {
          this.scrollToBottomHandlers = 
              this.scrollToBottomHandlers.filter(x => x !== handler)
      }
  }
  
  private triggerScrollToBottom(){
      this.scrollToBottomHandlers.forEach(h => h())

  }

  public update(
    left: number,
    top : number,
    offsetHeight : number,
    scrollHeight : number
  ) {
    this.left = left
    this.top = top
    this.scrollHeight = scrollHeight
    this.offsetHeight = offsetHeight
    if(this.bottomReached()) {
        this.triggerScrollToBottom()
    }        
  }

  public bottomReached() {
    return this.top + this.offsetHeight >= this.scrollHeight
  }
}

const useScroll = () => {

  const scrollInfo = useRef(new ScrollDescriptor())

  const scrollHandler : UIEventHandler<HTMLDivElement> = (e) => {
    const scroller = e.currentTarget
    const left = e.currentTarget.scrollLeft
    const top = e.currentTarget.scrollTop
    scrollInfo.current.update(left, top, scroller.offsetHeight, scroller.scrollHeight)
  }

  return {
    onScroll : scrollHandler,
    info : scrollInfo.current
  }
}

export const ScrollerExample = () => {
  const {onScroll, info} = useScroll()

  useEffect(() => {
    const unsub = info.onScrollToBottom(() => {
        console.log("bottom reached")
    })
    return () => {
        unsub()
    }
  }, [])
  return (
    <div
      onScroll={onScroll}
      style={{
        height: 600,
        width: 400,
        overflow: "scroll",
      }}
    >
      <div
        style={{
          height: 800,
          width: "100%",
          background: "red",
        }}
      ></div>
      <div
        style={{
          height: 800,
          width: "100%",
          background: "blue",
        }}
      ></div>
      <div
        style={{
          height: 800,
          width: "100%",
          background: "yellow",
        }}
      ></div>
    </div>
  )
}

状态封装

可以使用hooks进行状态的封装,例如之前我们实现的`受控` 组件和`非受控`组件的公共逻辑。

import { ChangeEventHandler, useEffect, useState } from "react"


export function useValue<T>({
  value,
  defaultValue,
  onChange,
}: {
  value?: T
  defaultValue?: T
  onChange?: (val : T) => void 
}): [T, (val: T) => void] {
  const controlled = typeof value !== "undefined"
  const [_value, setValue] = useState<T>(
    controlled ? value : defaultValue
  )
  useEffect(() => {
    if (controlled && value !== _value) {
      setValue(value)
    }
  }, [value])

  useEffect(() => {
    if (!controlled && value !== defaultValue) {
      onChange && onChange(value)
    }
  }, [_value])

  const setHandler = (val: T) => {
    if (!controlled) {
      setValue(val)
    } else {
      onChange && onChange(val)
    }
  }
  return [_value, setHandler]
}

链接外部能力

有时候我们需要链接外部的能力,比如说:使用一个外部的对象。

class SomeBuzObject {
    
    public getList(){
        return ([
            {...}, {...}, {...}
        ])
    }
                
    public onListChanged(handler :Function) {
        // ...
    }
}

这样的情况可以将对象放到`memo` 或者`ref` 中。然后再用`useEffect` 监听外部对象的变化,最后设置一个版本变量,用于更新组件。

const useBuz = () =>{
    const obj = useMemo(() => new SomeBuzObject(), [])        
    // or
    //const obj = useRef(new SomeBuzObject())
    const [, setV] = useState(0)
    useEffect(() => {
        obj.onListChanged(() => {
            setV(x => x + 1)
        })
    }, [])
    return obj
}
const Component = () => {
    
    const obj = useBuz()
    // ...
    return <div>
        {obj.getList().map((item) => {
            return <... />
        })}
    </div>
}

封装业务逻辑

Hooks也可以对于业务逻辑进行封装。

例子:封装分页逻辑

注意用`useEffect` 让page变化成为数据变化的因子,而不是将page看做单纯的一个请求数据。

async function request(path, page){
    const resp = await fetch(path + "?" + qs.stringify({page}))
    const data = await resp.json()    
    return data
}

function usePaging(path){
    
    const [page, setPage] = useState(0)    
    const [list, setList] = useState([])
    
    useEffect(() => {
        request(path, page)
        	.then(json =>{
            setList(json.data.list)
           })
    }, [page])

    return {
        list,
        next : () => setPage(x => x + 1),
        prev : () => setPage(x => Math.max(0, x - 1)),
    }
}

const SomeComponent = () => {
    
    const {list, next, prev} = usePaging("/products")
    
    // 绘制逻辑
}

1

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-16 11:16:35  更:2022-05-16 11:17:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 20:34:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码