结尾
这是第 64 篇不掺水的原创,想获取更多原创好文,请搜寻公众号关注咱们吧~ 本文首发于政采云前端博客:“混合双打”之如何在 Class Components 中应用 React Hooks
前情提要
React 在 v16.8.0 版本中推出了 Hook,作为纯函数组件的加强,给函数组件带来了状态、上下文等等;之前一篇对于 React Hooks 的文章介绍了如何应用一些官网钩子和如何自建钩子,如果想要理解这些内容的同学能够点击这里。
本文不会再介绍上文中已提到的局部钩子的根底应用,而是次要着眼解决一些理论开发中的场景。
现状
Class Component 外部简单的生命周期函数使得咱们组件外部的 componentDidMount
越来越简单和臃肿,独立组件动辄上千行代码;组件嵌套层级越来越深,组件之间的状态复用也变得十分艰难。
Hook 无疑是可选的,他不会对现有我的项目造成任何冲击和毁坏,社区对于它的劣势也有过很多探讨;不过目前官网也没有打算移除 Class,而是举荐渐进式的去应用 Hook,在一些新增的组件中优先选用 Hook。那么咱们想要在原有以 Class Component 为主的我的项目中开始应用 Hook,与原有的 Class Component 必然会产生交互,是不是须要将这些 Class Component 重写为 Hook 呢?
将局部简单的 Class Component 逐渐重写为 Hook 应该排在我的项目迭代的中长期打算中,如果想要在一个迭代中进行大量革新,带来的微小老本和副作用也是无法估量的。
那么短期内咱们就绕不开 Hook 与 Class 组件的混合应用。
解决方案
先简略介绍一下两种组件的根本写法:
Class Components:类组件的写法
export default class ShowHook extends Component { return ( <h1>Hello Hook!</h1> );}
Function Components:Hook 组件的写法
function ShowHook (props){ return ( <h1>Hello Hook!</h1> );}
混合应用就难以避免的须要进行通信和参数传递,上面我用一个简略的解决模块显示暗藏的性能组件 ShowHook
作为一个例子,介绍三种是比拟常见混合应用的形式,先来看一下成果:
1.Render props
Render props 中来自父组件的 props children 是一个 Function
,咱们能够将子组件的外部变量通过函数传递至父组件,达到通信的目标。
// 子组件 SayHello.jsimport React, { useState } from 'react';function sayHello({ children }) { const [visible, changeVisible] = useState(false); const jsx = visible && ( <h1 onClick={() => changeVisible(false)}> Hello Hook! </h1> ); return children({ changeVisible, jsx });}export default sayHello;
父组件获取到 changeVisible
办法之后就能不便的管制 visible
的状态。
// 父组件 ShowHook.jsimport React, { Component, Fragment } from 'react';import SayHello from '../components/SayHello';export default class ShowHook extends Component { render() { return ( <SayHello> {({ changeVisible, jsx }) => { return ( <React.Fragment> <button onClick={() => changeVisible(true)}> showChild </button> {jsx} </React.Fragment> ); }} </SayHello> ); }}
props.children
罕用的类型是字符串、对象甚至数组;但其实咱们也能够传入一个函数,只有最终能返回出DOM 树即可;Render props 是将 Render 局部抽离进去作为函数传入子组件;它次要的作用是将 state 局部抽成组件,实现 state 的复用。
// 封装子组件function Mouse (props) { const [position, setPosition] = useState({x: 0,y: 0}); const handleMouseMove = (e) => { setPosition({ x: e.clientX, y: e.clientY }) } return ( <div onMouseMove={handleMouseMove}> {this.props.children(position)} </div> )}// 应用场景 1:图片地位追随鼠标class Cat1 extends React.Component { render() { return ( <Mouse> {(position) => <img src="/cat.jpg" style={{ position: 'absolute', left: position.x, top: position.y }} /> } </Mouse> ) }}// 应用场景 2:页面展现鼠标坐标class Cat2 extends React.Component { render() { return ( <Mouse> {(position) => <h1>x: {position.x} y: {position.y}</h1> } </Mouse> ) }}
下面应用了 React 官网文档中的例子进行改写,具体成果如下:
场景 1:
场景 2:
2.应用 HOC
HOC (Higher-Order Components) 是另一种进步代码复用率的常见技巧,它接管一个组件作为参数,最终返回出一个新的组件。
上面的办法使得 button
管制任意组件显示暗藏的性能被封装为高阶组件,得以复用,并且 setVisible
办法也能被传递到 Class Component
中。
// 高阶组件 SayHello.jsimport React, { useState, Fragment } from 'react';const sayHello = (Component) => { return (props) => { const [visible, setVisible] = useState(false); return ( <React.Fragment> <button onClick={() => setVisible(true)}> showChild </button> {visible && <Component changeVisible={setVisible} visible={visible} />} </React.Fragment> ); };};export default sayHello;
在内部 Class Component 中咱们能够定制受外部显示/暗藏管制的组件,并且应用高阶组件中向外传递的 props 。
// ShowHook.jsimport React, { Component } from 'react';import SayHello from '../components/SayHello';class ShowHook extends Component {render() { const { changeVisible } = this.props; return ( <h1 onClick={() => changeVisible(false)}> Hello Hook! </h1> );}}export default SayHello(ShowHook);
HOC 在理论应用中是将一些副作用函数、专用办法作为组件抽取进去,从而晋升复用率;咱们能够把父组件的render
局部改为一个弹窗,或任意内容使得子组件失去复用,例如:
// 复用高阶组件 SayHelloimport React, { Component } from 'react';import SayHello from '../components/SayHello';import { Modal } from 'antd';class ShowModal extends Component { render() { const { changeVisible, visible } = this.props; return ( <Modal title="Basic Modal" visible={visible} onOk={() => changeVisible(false)} onCancel={() => changeVisible(false)} > <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Modal> ); }}export default SayHello(ShowHook);
这样就能够轻松的管制弹窗的显示暗藏;实际效果如下:
3.useImperativeHandle & Refs 转发 (React.forwardRef)
Ref 转发是一项将 Ref 主动地通过组件传递到其一子组件的技巧。对于大多数利用中的组件来说,这通常不是必须的,但其对某些组件,尤其是可重用的组件库是很有用的。
它能够将子组件的办法裸露给父组件应用。
// 父组件 ShowHook.jsimport React, { Component } from 'react';import SayHello from './SayHello';export default class ShowHook extends Component { showChild = () => { console.log(this.child); //能够看到 changeVisible 办法被挂载到了 this.child 下 // {changeVisible: f()} this.child.changeVisible(true); } // 将子组件裸露进去的对象挂载到 child onRef = (ref) => { this.child = ref; } render() { return ( <React.Fragment> <button onClick={this.showChild}>showChild</butotn> <SayHello ref={this.onRef} /> </React.Fragment> ); }}// 子组件 SayHello.jsimport React, { useState, useImperativeHandle, forwardRef } from 'react';function SayHello(props, ref) { const [visible, changeVisible] = useState(false); // 裸露的子组件办法,给父组件调用 useImperativeHandle(ref, () => { return { changeVisible, }; }); return visible && ( <h1 onClick={() => changeVisible(false)}> Hello Hook! </h1> );}export default forwardRef(SayHello);
下面例子中封装了一个子组件,任意一个应用了该子组件的中央都能够管制它的状态。
结束语
目前 Hooks 尚不具备残缺的 Class Component 的性能,一些不罕用的生命周期函数尚不反对,例如:getSnapshotBeforeUpdate
, getDerivedStateFromError
以及 componentDidCatch
,但官网已将他们 排入打算内,置信不久之后就会失去反对;将来 Hooks 可能将成为 React Components 的首选,在现阶段就让咱们欢快的混合应用吧。
参考文章
How to Use React Hooks in Class Components
React拾遗:Render Props及其应用场景
Hooks FAQ
招贤纳士
政采云前端团队(ZooTeam),一个年老富裕激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 40 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员形成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端利用、数据分析及可视化等方向进行技术摸索和实战,推动并落地了一系列的外部技术产品,继续摸索前端技术体系的新边界。
如果你想扭转始终被事折腾,心愿开始能折腾事;如果你想扭转始终被告诫须要多些想法,却无从破局;如果你想扭转你有能力去做成那个后果,却不须要你;如果你想扭转你想做成的事须要一个团队去撑持,但没你带人的地位;如果你想扭转既定的节奏,将会是“5 年工作工夫 3 年工作教训”;如果你想扭转原本悟性不错,但总是有那一层窗户纸的含糊… 如果你置信置信的力量,置信平凡人能成就不凡事,置信能遇到更好的本人。如果你心愿参加到随着业务腾飞的过程,亲手推动一个有着深刻的业务了解、欠缺的技术体系、技术发明价值、影响力外溢的前端团队的成长历程,我感觉咱们该聊聊。任何工夫,等着你写点什么,发给 ZooTeam@cai-inc.com