react.js高级用法

⾼阶组件⽤法及封装

⾼阶组件(HOC)是 React 中⽤于复⽤组件逻辑的⼀种⾼级技巧。HOC ⾃身不是 React API 的⼀部分,它是⼀种基于 React 的组合特性⽽形成的设计模式。简单点说,就是组件作为参数,返回值也是组件的函数,它是纯函数,不会修改传⼊的组件,也不会使⽤继承来复制其⾏为。相反,HOC 通过将组件包装在容器组件中来组成新组件。HOC 是纯函数,没有副作⽤。

使⽤HOC的原因
  1. 抽取重复代码,实现组件复⽤:相同功能组件复⽤
  2. 条件渲染,控制组件的渲染逻辑(渲染劫持):权限控制。
  3. 捕获/劫持被处理组件的⽣命周期,常⻅场景:组件渲染性能追踪、⽇志打点。
HOC实现⽅式
属性代理

使⽤组合的⽅式,将组件包装在容器上,依赖⽗⼦组件的⽣命周期关系来;

  1. 返回stateless的函数组件
  2. 返回class组件
  • 操作props
// 可以通过属性代理,拦截⽗组件传递过来的porps并进⾏处理。
// 返回⼀个⽆状态的函数组件
function HOC(WrappedComponent) {
  const newProps = { type: 'HOC' };
  return props => <WrappedComponent {...props} {...newProps}/>;
}
// 返回⼀个有状态的 class 组件
function HOC(WrappedComponent) {
  return class extends React.Component {
    render() {
      const newProps = { type: 'HOC' };
      return <WrappedComponent {...this.props} {...newProps}/>;
   }
 };
}
  • 抽象state
// 通过属性代理⽆法直接操作原组件的state,可以通过props和cb抽象state
function HOC(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        name: '',
     };
      this.onChange = this.onChange.bind(this);
   }
    
    onChange = (event) => {
      this.setState({
        name: event.target.value,
     })
   }
    
    render() {
      const newProps = {
        name: {
          value: this.state.name,
          onChange: this.onChange,
       },
     };
      return <WrappedComponent {...this.props} {...newProps} />;
   }
 };
}
// 使⽤
@HOC
class Example extends Component {
  render() {
    return <input name="name" {...this.props.name} />;
 }
}
  • 通过props实现条件渲染
// 通过props来控制是否渲染及传⼊数据
import * as React from 'react';
function HOC (WrappedComponent) {
  return (props) => (
  <div>
   {
      props.isShow ? (
        <WrappedComponent
         {...props}
        />
     ) : <div>暂⽆数据</div>
   }
  </div>
 );
}
export default HOC;
  • 其他元素wrapper传⼊的组件
function withBackgroundColor(WrappedComponent) {
  return class extends React.Component {
    render() {
      return (
        <div style={{ backgroundColor: '#ccc' }}>
            <WrappedComponent {...this.props} {...newProps} />
        </div>
     );
   }
 };
}
反向继承

使⽤⼀个函数接受⼀个组件作为参数传⼊,并返回⼀个继承了该传⼊组件的类组件,且在返回组件的render() ⽅法中返回 super.render() ⽅法

const HOC = (WrappedComponent) => {
  return class extends WrappedComponent {
    render() {
      return super.render();
   }
 }
}
  1. 允许HOC通过this访问到原组件,可以直接读取和操作原组件的state/ref等;
  2. 可以通过super.render()获取传⼊组件的render,可以有选择的渲染劫持;
  3. 劫持原组件⽣命周期⽅法
function HOC(WrappedComponent){
  const didMount = WrappedComponent.prototype.componentDidMount;
  
  // 继承了传⼊组件
  return class HOC extends WrappedComponent {
    async componentDidMount(){
      // 劫持 WrappedComponent 组件的⽣命周期
      if (didMount) {
        await didMount.apply(this);
     }
      ...
   }
    render(){
      //使⽤ super 调⽤传⼊组件的 render ⽅法
      return super.render();
   }
 }
}
  • 读取/操作原组件的state
function HOC(WrappedComponent){
  const didMount = WrappedComponent.prototype.componentDidMount;
  // 继承了传⼊组件
  return class HOC extends WrappedComponent {
    async componentDidMount(){
      if (didMount) {
        await didMount.apply(this);
     }
      // 将 state 中的 number 值修改成 2
      this.setState({ number: 2 });
   }
    render(){
      //使⽤ super 调⽤传⼊组件的 render ⽅法
      return super.render();
   }
 }
}
  • 条件渲染
const HOC = (WrappedComponent) =>
  class extends WrappedComponent {
    render() {
      if (this.props.isRender) {
        return super.render();
     } else {
        return <div>暂⽆数据</div>;
     }
   }
 }
  • 修改react树
// 修改返回render结果
function HigherOrderComponent(WrappedComponent) {
  return class extends WrappedComponent {
    render() {
      const tree = super.render();
      const newProps = {};
      if (tree && tree.type === 'input') {
        newProps.value = 'something here';
     }
      const props = {
        ...tree.props,
        ...newProps,
     };
      const newTree = React.cloneElement(tree, props,
tree.props.children);
      return newTree;
   }
 };
}
属性代理和反向继承对比
  1. 属性代理:从“组合”⻆度出发,有利于从外部操作wrappedComp,可以操作props,或者在
    wrappedComp 外加⼀些拦截器(如条件渲染等);
  2. 反向继承:从“继承”⻆度出发,从内部操作wrappedComp,可以操作组件内部的state,⽣命周期和render等,功能更加强⼤;

Hooks详解

Hooks是react16.8以后新增的钩⼦API;
⽬的:增加代码的可复⽤性,逻辑性,弥补⽆状态组件没有⽣命周期,没有数据管理状态state的缺陷。
为什么要使⽤Hooks?

  1. 开发友好,可扩展性强,抽离公共的⽅法或组件,Hook 使你在⽆需修改组件结构的情况下复⽤状态逻辑;
  2. 函数式编程,将组件中相互关联的部分根据业务逻辑拆分成更⼩的函数;
  3. class更多作为语法糖,没有稳定的提案,且在开发过程中会出现不必要的优化点,Hooks⽆需学习复杂的函数式或响应式编程技术;
常⻅Hooks
useState
const [number, setNumber] = useState(0);
  1. setState⽀持stateless组件有⾃⼰的state;
  2. ⼊参:具体值或⼀个函数;
  3. 返回值:数组,第⼀项是state值,第⼆项负责派发数据更新,组件渲染;注意:setState会让组件重新执⾏,所以⼀般需要配合useMemo或useCallback;
const DemoState = (props) => {
   /* number为此时state读取值 ,setNumber为派发更新的函数 */
   const [number, setNumber] = useState(0) /* 0为初始值 */
   return (
     <div>
       <span>{ number }</span>
       <button onClick={ ()=> {
         setNumber(number + 1)
         console.log(number) /* 这⾥的number是不能够即使改变的,返回0 */
         }}
        />
     </div>
   )
}
// 当更新函数之后,state的值是不能即时改变的,只有当下⼀次上下⽂执⾏的时候,state值才
随之改变
——————————————————————————————————————————
const a =1
const DemoState = (props) => {
   /* useState 第⼀个参数如果是函数 则处理复杂的逻辑,返回值为初始值 */
   let [number, setNumber] = useState(()=>{
      // number
      return a === 1 ? 1 : 2
   }) /* 1为初始值 */
   return (<div>
       <span>{ number }</span>
       <button onClick={ ()=>setNumber(number+1) } ></button>
   </div>)
}
useEffect
  1. 使⽤条件:当组件init、dom render完成、操纵dom、请求数据(如componentDidMount)等;
  2. 不限制条件,组件每次更新都会触发useEffect -->componentDidUpdate 与componentwillreceiveprops;
  3. useEffect 第⼀个参数为处理事件,第⼆个参数接收数组,为限定条件,当数组变化时触发事件,为[]只在组件初始化时触发;
  4. useEffect第⼀个参数有返回时,⼀般⽤来消除副作⽤(如去除定时器、事件绑定等);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值