关于react.js:面试官你是怎样进行react组件代码复用的

6次阅读

共计 4955 个字符,预计需要花费 13 分钟才能阅读完成。

mixin

Mixin 设计模式

Mixin(混入)是一种通过 扩大收集性能 的形式,它实质上是将一个对象的属性拷贝到另一个对象下面去,能够拷贝多个属性到一个对象上,为了解决代码复用问题。

罕用的办法:JQuery 的 extend 办法。

var LogMixin = {log: function() {console.log('log');
  },
  componentDidMount: function() {console.log('in');
  },
  componentWillUnmount: function() {console.log('out');
  }
};

var User = React.createClass({mixins: [LogMixin],
  render: function() {return (<div>...</div>)
  }
});

var Goods = React.createClass({mixins: [LogMixin],
  render: function() {return (<div>...</div>)
  }
});


毛病

  1. Mixin 可能会相互依赖,互相耦合,不利于代码保护
  2. 不同的 Mixin 中的办法可能会互相抵触
  3. 当初大量应用 ES6 语法后,React.createClass 曾经勾销,这种形式也不再举荐

高阶组件(HOC)

高阶组件的定义:

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。(高阶组件是参数为组件,返回值为新组件的函数。)

具体的意思就是:
高阶组件能够看作 React 对装璜模式的一种实现,高阶组件就是一个函数,且该函数承受一个组件作为参数,并返回一个新的组件。他会返回一个加强的 React 组件。高阶组件能够让咱们的代码更具备复用性,逻辑性与抽象性,能够对 render 办法进行劫持,也能够管制 props 与 state。

const EnhancedComponent = higherOrderComponent(WrappedComponent);

实现高阶组件的两种形式:

  1. 属性代理:高阶组件通过被包裹的 React 组件来操作 props
  2. 反向继承:高阶组件继承于被包裹的 React 组件。

属性代理

import React,{Component} from 'react';

const HOC = (WrappedComponent) =>
  class WrapperComponent extends Component {state = { number: 0};
    btnClick = () => {
        this.setState({number: this.state.number++})
    }
    render() {
        const newProps = {
            btnClick: this.btnClick,
            number: this.state.number
        }
        return (
            <div>
                rere HOC
                <WrappedComponent {...this.props} {...this.newProps} />
            </div>
        )
    }
}

export default HOC;

class MyComponent extends Component{//...}

export default HOC(MyComponent)

这里最重要的局部是render 办法中返回的 WrappedComponent 的 React 组件,这样就能够通过高阶组件来传递 props,这就是属性代理。

这样组件就能够一层层地作为参数被调用,原始组件就具备了高阶组件对它的润饰,也放弃了单个组件的封装性,与易用性。

特点

  1. 管制 props
    咱们能够在 HOC 外面对 props 进行增删查改等操作

    const MouseHoc = (MouseComponent, props) => {
       props.text = props.text + "---I can operate props";
       return class extends React.Component {render() {
               return (<div style={{ height: "100%"}} onMouseMove={this.handleMouseMove}>
                       <MouseComponent {...props} mouse={this.state} />
                   </div>
               );
           }
       };
    };
    MouseHoc(Mouse, {text: "some thing..."});
    
  2. 通过 refs 应用援用

    function refHOC(WrappedComponent) {
        return class extends Component {componentDidMount() {this.wapperRef.log();
            }
            render() {
                return (
                    <WrappedComponent
                        {...this.props}
                        ref={ref => {this.wapperRef = ref;}}
                    />
                );
            }
        };
    }
    
  3. 形象 state
  4. 渲染劫持
    高阶组件能够在 render 函数中做十分多的操作,从而管制原组件的渲染输入。只有扭转了原组件的渲染,咱们都将它称之为一种渲染劫持。参考 前端 react 面试题具体解答

    function visibleHOC(WrappedComponent) {
       return class extends Component {render() {if (this.props.visible === false) return null;
               return <WrappedComponent {...props} />;
           }
       };
    }
    
  5. 应用其余元素包裹 WrappedCompoennt
    批改 props

反向继承

const MyContainer = (WrappedComponent) =>
    class extends WrappedComponent{render(){return super.render();
        }
    }

这里返回的组件继承了 WrappedComponent,因为被动地继承了 WrappedComponent,所有的调用都会反向。

注意事项

  1. 当咱们利用 HOC 去加强另一个组件时,咱们理论应用的组件曾经不是原组件了,所以咱们拿不到原组件的任何动态属性,咱们能够在 HOC 的结尾手动拷贝他们

    function proxyHOC(WrappedComponent) {
       class HOCComponent extends Component {render() {return <WrappedComponent {...this.props} />;
           }
       }
       HOCComponent.staticMethod = WrappedComponent.staticMethod;
       // ...
       return HOCComponent;
    }
    
    
  2. 不要在 render 办法内创立高阶组件
  3. 不要扭转原始组件(高阶组件就是一个没有副作用的纯函数。)
  4. 透传不相干的 props

解决的问题

  1. 高阶组件就是一个没有副作用的纯函数,各个高阶组件不会相互依赖耦合
  2. 高阶组件也有可能造成抵触,但咱们能够在恪守约定的状况下防止这些行为
  3. 高阶组件并不关怀数据应用的形式和起因,而被包裹的组件也不关怀数据来自何处。高阶组件的减少不会为原组件减少累赘

存在的问题

  1. HOC 须要在原组件上进行包裹或者嵌套,如果大量应用 HOC,将会产生十分多的嵌套,这让调试变得十分艰难
  2. HOC 能够劫持 props,存在雷同名称的 props,则存在笼罩问题在不恪守约定的状况下也可能造成抵触,而且 react 并不会报错。
  3. 当存在多个 HOC 时,你不晓得 Props 是从哪里来的。
  4. HOC 属于动态构建, 动态构建即是从新生成一个组件,即返回的新组件,不会马上渲染,即新组件中定义的生命周期函数只有新组件被渲染时才会执行。

** 在这个范式下,代码通过一个相似于 装璜器(decorator)的技术进行共享。首先,你的一个组件定义了大量须要被渲染的标记,之后用若干具备你想用共享的行为的组件包裹它。因而,你当初是在 装璜 你的组件,而不是混入你须要的行为!

Render props

Render Props 从名知义,也是一种剥离重复使用的逻辑代码,晋升组件复用性的解决方案。在被复用的组件中,通过一个名为“render”(属性名也能够不是 render,只有值是一个函数即可)的属性,该属性是一个函数,这个函数承受一个对象并返回一个子组件,会将这个函数参数中的对象作为 props 传入给新生成的组件

它的特点

  1. 传入函数的属性,就是 想要共享的 state,这个雷同的 state 是组件的状态,或者行为
  2. 术语“render prop”是指一种技术,用于应用一个值为函数的 prop 在 React 组件之间的代码共享。
  3. render prop 仅仅就是一个函数。
  4. render prop是一种模式,重点是 prop,而不是 render,任何被用于告知组件须要渲染什么内容的函数 prop 在技术上都能够被称为“render prop”.
  5. 这里的组合模型是 动静的!每次组合都产生在 render 外部,因而,咱们就能利用到 React 生命周期以及天然流动的 props 和 state 带来的劣势。
  6. 具备 render prop 的组件承受一个函数,该函数返回一个 React 元素并调用它,而不是实现本人的渲染逻辑

小栗子

<DataProvider render={data => (<h1>Hello {data.target}</h1>
)}/>

劣势

  1. 不必放心 Props 是从哪里来的,它只能从父组件传递过去。
  2. 不必放心 props 的命名问题。
  3. render props 是动静构建的。

能够用 render props来代替 HOC

const withMouse = (Component) => {
  return class extends React.Component {render() {
      return <Mouse render={mouse => (<Component {...this.props} mouse={mouse}/>
      )}/>
    }
  }
}

Hook

在 Hooks 呈现以前,咱们总是纠结的问题:

  1. 无状态组件 VS Class 组件
  2. 生命周期
    componentDidMount 和 componentDidUpdate 须要做雷同的事件
  3. this 指向
    为了保障 this 的指向正确,咱们常常这么写

    this.handleClick = this.handleClick.bind(this)
    <button onClick={() => this.handleClick(e)}>
    
  4. HOC 和 render props 减少咱们代码的层级关系

动机

Hook 的作用

  1. 咱们的函数变成了一个有状态的函数
  2. Hooks 实质上就是一类非凡的函数,它们能够为你的函数型组件(function component)注入一些非凡的性能(生命周期钩子的性能:useEffect;上下文(context):useContext)
  3. 解决 this 指向问题

State Hooks

Effect Hooks

咱们写的有状态组件,通常会产生很多的副作用(side effect)。之前都把这些副作用的函数写在生命周期函数钩子里,比方 componentDidMount,componentDidUpdate 和 componentWillUnmount。而当初的 useEffect 就相当与这些申明周期函数钩子的集合体。它以一抵三。

用 Effect Hooks 来解决这个这些副作用。

留神点

  1. react 首次渲染和之后的每次渲染都会调用一遍传给 useEffect 的函数。而之前咱们要用两个申明周期函数来别离示意首次渲染(componentDidMount),和之后的更新导致的从新渲染(componentDidUpdate)。
  2. 函数是异步执行的,而之前的 componentDidMount 或 componentDidUpdate 中的代码则是同步执行的
  3. 怎么解绑副作用
  4. 跳过一些不必要的副作用函数

应用范畴

只能在 React 函数式组件或自定义 Hook 中应用 Hook。

Hook 的提出次要就是为了解决 class 组件的一系列问题,所以咱们不能在 class 组件中应用它。

相比函数,编写一个 class 可能须要把握更多的常识,须要留神的点也越多,比方 this 指向、绑定事件等等。另外,计算机了解一个函数比了解一个 class 更快。Hooks 让你能够在 classes 之外应用更多 React 的新个性。

正文完
 0