2-2-9 & 10 & 11 React Hooks 封装公共行为

Posted 沿着路走到底

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

以上是关于2-2-9 & 10 & 11 React Hooks 封装公共行为的主要内容,如果未能解决你的问题,请参考以下文章

JAVA位赋值条件运算符等

计算几何DPtarjanDay 10.6

P & R 11

快速排序

NO10——各种欧几里得

R语言的基本操作--读取和写入txt,sapply&lapply