银川怎么做网站,百度知道问答首页,做网站数据库表各字段详情,网站背景素材作者 | #x1f47d;来源 | 前端Sharing前言懂得 JSX 本质的同学都知道它只不过是一种语法糖#xff0c;会被 babel 处理成 createElement 的形式#xff0c;最后再变成常规的 js 对象。所以#xff0c;我们就可以在 js 逻辑层面对 element 对象做处理#xff0c;自定义 … 作者 | 来源 | 前端Sharing前言懂得 JSX 本质的同学都知道它只不过是一种语法糖会被 babel 处理成 createElement 的形式最后再变成常规的 js 对象。所以我们就可以在 js 逻辑层面对 element 对象做处理自定义 hooks 作为 element 逻辑处理层也就变得理所当然了。本文我们就来研究一下自定义 hooks 的一些其他的用途以及怎么样处理视图层还有一些新玩法。用 hooks 处理 element 对象场景一hooks 处理 element 的案例已经屡见不鲜了。比如我们相对一些 UI 层的内容做缓存处理像如下场景。function Test(){console.log(test rerender)return divhello, react !/div
}function Index({ value }){const [ number , setNumber ] React.useState(0)const element React.useMemo(() Test / ,[ value ])return div{element}button onClick{() setNumber(number 1 )} 点击 {number} /button/div
}如上用useMemo缓存处理 Test 组件对应的 element 对象之后当 Index 中的 value 改变的时候才会再次执行 useMemo 得到新的 element 对象。当点击按钮的时候会触发 setNumber 改变 state会触发 Index 的更新但是 useMemo 会直接读取缓存的值这样性能上的体验就是 Test 不会再更新。这是一种基于 hooks 的实现的优化策略本质上是对 element 的缓存。这种方案处理后 Index 不再需要类似于 HOC 的 memo 组件包裹。可以根据条件和方向做渲染上定制方向上的优化这是一种父 - 子的优化方案。还有一些更为复杂的场景就是多个 hooks 组合起来来达到目的。function Index(){const [ number , setNumber ] React.useState(0)const { value } React.useContext(valueContext)const element React.useMemo(() Test / ,[ value ])return div{element}button onClick{() setNumber(number 1 )} 点击 {number} /button/div
}通过useContext读取valueContext中的 value 属性 Test 组件订阅 value 的变化当 context 里面的 value 改变的时候重新生成 element 对象也就是重新渲染 Test 组件。场景二react router v6 出来之后有一个全新的 hooks —— useRoutes。它可以接受路由的配置的 js 路由树返回一个视图层的 element tree。我们看一下具体使用。const routeConfig [{path:/home,element:Home /},{path:/list/:id,element:List /},{path:/children,element:Layout /,children:[{ path:/children/child1 , element: Child1/ },{ path:/children/child2 , element: Child2/ }]}
]const Index () {const element useRoutes(routeConfig)return div classNamepage div classNamecontent Menus /{element}/div/div
}
const App () BrowserRouterIndex //BrowserRouteruseRoutes 为自定义 hooks 返回规范化的路由结构。hooks 不再像我们平时那样只负责逻辑的处理此场景下hooks 完全充当了一个视图容器。这个模式下对自定义 hooks 理解打破了传统观念可能这种由逻辑层到视图层的转化会让一部分同学不适应不过这些不重要我们要有一个思维上的转变这才显得重要。设计模式下面设想一个场景自定义 hooks 可不可以实现一种设计场景可以类似于组合模式和 hoc 模式的结合可以实现逻辑和视图的分离呢1、传统的组合模式缺点首先看一下组合模式传统的组合模式如下所示function Index(){return GrandFatherFatherSon{null}/Son/Father/GrandFather
}上面通过 GrandFather Father Son 三个组件进行组合模式。这种模式下组合的内外层组件需要建立关联和通信的话需要通过 cloneElement 混入一些通信的方法。以上面为例子如果想要实现 Father —— Son 双向通信我们需要这么处理/* 父组件 */
function Father({ children }){const [ fatherSay , setFatherSay ] React.useState()const toFather () console.log(son to father)const element React.cloneElement(children,{ fatherSay ,toFather })return divp Father /pbutton onClick{() setFatherSay(father to son)} to Son/button{element}/div
}/* 子组件 */
function Son({ children, fatherSay, toFather }){console.log(fatherSay)return divp son /pbutton onClick{toFather} to Father/button{children || null}/div
}如上Father 组件通过 cloneElement 向 props 中混入 toFather 方法。Son 组件可以直接通过 props 拿到此方法向父组件通信实现 Son - Father。Father 可以通过 useState 改变 fatherSay 并且传递给 Son实现 Father - Son。有一个显而易见的弊端就是toFather cloneElement 等逻辑需要开发者去单独处理也就是逻辑层和 ui 层是强关联的。这就需要开发者在组合模式的上下层组件中分别处理逻辑。如果再加上 GrandFather 组件那么就需要像下图一样处理2、hoc 嵌套提供 ideahoc 本身就是一个函数接收原始组件返回新的组件多个 hoc 可以嵌套。function Index(){/* .... */
}
export default HOC1(styles)(HOC2( HOC3(Index) ))HOC1 - HOC2 - HOC3 - Index那么可不可以用 hoc 这个思想来实现组合模式呢并且解决逻辑冗余呢。3、用自定义 hooks 实现结合最开始讲到的可以通过自定义 hooks 来处理 ui 逻辑那么就能通过类似 hoc 的多层嵌套 hooks解决组合模式的上述缺陷。那么自定义的 hooks 的设计如下useComposeHooks( component, Layout , mergeProps )component 为需要通过组合模式处理的组件。需要组合的容器组件。mergeProps 需要合并的新的 props 。useComposeHooks 可以多个嵌套使用。比如如下function Index(){const element useComposeHooks( useComposeHooks( useComposeHooks(...) , Layout2,mergeProps ) ,Layout1,mergeProps)return element
}等价于Layout1Layout2{ ... }/Layout2
/Layout1接下来我们去实现这个功能。代码实现及效果验证1、编写 useComposeHooks接下来我们编写一下 useComposeHooksfunction useComposeHooks(component, layout, mergeProps) {const sonToFather useRef({})const fatherToSon useRef({})/* 子对父组件通信 */const sonSay React.useCallback((type, payload) {const cb sonToFather.current[type]typeof cb function cb(payload)}, [component])/* 父监听子组件 */const listenSonSay React.useCallback((type, fn) {sonToFather.current[type] fn}, [layout])/* 父对子组件通信*/const fatherSay React.useCallback((type,payload){const cb fatherToSon.current[type]typeof cb function cb(payload)},[layout])/* 子监听父组件 */const listenFather React.useCallback((type,fn){fatherToSon.current[type] fn},[ component ])const renderChildren React.useMemo(() {return component ? React.cloneElement(component, { listenFather, sonSay }) : null}, [component])return layout ? React.createElement(layout, { fatherSay,listenSonSay, ...mergeProps, children: renderChildren }) : renderChildren
}通过 useRef 保存通信方法。编写 sonSay 子对父组件通信listenSonSay 父监听子组件fatherSay父对子组件通信listenFather子监听父组件方法。通过 cloneElement 克隆内层组件。通过 createElement 创建外层组件。2、测试 demofunction GrandFather({ name, children }) {return divp {name} /p{children}/div
}function Father({ children, listenSonSay, name ,fatherSay}) {listenSonSay(sonSay, (message) console.log(message))return divp {name} /pbutton onClick{() fatherSay(fatherSay,hello,son!)} to Son/button{children}/div
}function Son({ children, sonSay,listenFather ,name }) {listenFather(fatherSay,(message) console.log(message) )return divp {name} /pbutton onClick{() sonSay(sonSay, hello,father!)} to Father/button{children || null}/div
}
export default function Index() {return (useComposeHooks(useComposeHooks(useComposeHooks(null, Son, { name: Son }), Father, { name: Father }), GrandFather, { name: GrandFather }))
}如上我们不再需要向业务层做其他的处理。只需要调用 props 里面的相关方法就可以了。接下来看一下效果(非动图)如上完美实现了。通过这个案例主要向大家展示自定义 hooks 实现了组合模式。不要太关注代码的细节。总结今天通过一个创意想法讲述了自定义 hooks 的一些其他玩法当然本文中的 demo 只是一个案例并不能使用在真实的业务场景下通过本文希望大家对 hooks 有一个全新的理解。往期推荐如果让你来设计网络Docker从入门到实战过程全记录没有操作系统程序可以运行起来吗如何在 Kubernetes Pod 内进行网络抓包点分享点收藏点点赞点在看