首页 > 其他分享 >面试官:你是怎样进行react组件代码复用的

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

时间:2023-01-03 09:44:23浏览次数:49  
标签:React 面试官 HOC render 复用 react props 组件 高阶

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%" }} onm ouseMove={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 函数中做非常多的操作,从而控制原组件的渲染输出。只要改变了原组件的渲染,我们都将它称之为一种渲染劫持。

    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 元素并调用它,而不是实现自己的渲染逻辑

### 小栗子

```xml
<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 的新特性。

标签:React,面试官,HOC,render,复用,react,props,组件,高阶
From: https://www.cnblogs.com/beifeng1996/p/17021098.html

相关文章

  • 阿里前端二面必会react面试题总结
    非嵌套关系组件的通信方式?即没有任何包含关系的组件,包括兄弟组件以及不在同一个父级中的非兄弟组件。可以使用自定义事件通信(发布订阅模式)可以通过redux等进行全局状态......
  • React中组件之间是如何通信的 react的组件通信方式有哪些
    一、是什么通信指的是发送者通过某种媒体以某种格式来传递信息到收信者以达到某个目的,广义上,任何信息的传递都是通信二、如何通信?组件传递的方式有很多种,根据传送......
  • react 项目的性能优化
    react项目的性能优化有哪些?1、react模块化处理就是将react内容进行模块化划分,一个模块一个组件,react更新机制是组件重新更新2、在react项目中更新数据,不要直接将......
  • 重新捋一捋React源码之更新渲染流程
    前言前些天在看DanAbramov个人博客(推荐阅读,站在React开发者的角度去解读一些API的设计初衷和最佳实践)里的一篇文章,其重点部分的思想就是即使不使用Memo(),也可以通过组合......
  • 面试官:React怎么做性能优化
    前言最近一直在学习关于React方面的知识,并有幸正好得到一个机会将其用在了实际的项目中。所以我打算以博客的形式,将我在学习和开发(React)过程中遇到的问题记录下来。这两......
  • 面试官让你说说react状态管理?
    开发者普遍认为状态是组件的一部分,但是同时却又在剥离状态上不停的造轮子,这不是很矛盾么?对于一个最简单的文本组件而言functionText(){const[text,setText]=......
  • 校招前端一面经典react面试题(附答案)
    React.forwardRef是什么?它有什么作用?React.forwardRef会创建一个React组件,这个组件能够将其接受的ref属性转发到其组件树下的另一个组件中。这种技术并不常见,但在以下......
  • 2022前端二面react面试题(边面边更)
    何为JSXJSX是JavaScript语法的一种语法扩展,并拥有JavaScript的全部功能。JSX生产React"元素",你可以将任何的JavaScript表达式封装在花括号里,然后将其嵌入到JS......
  • 【React自学笔记08】React18Hook补充
    关于钩子函数的使用注意事项:钩子只能在React组件和自定义钩子中使用钩子不能在嵌套函数或其他语句(if、switch、white、for等)中使用React中自带的钩子函数useStateu......
  • 面试官:系统需求多变时如何设计?
    面试官:我想问个问题哈,项目里比较常见的问题面试官:我现在有个系统会根据请求的入参,做出不同动作。但是,这块不同的动作很有可能是会发生需求变动的,这块系统你会怎么样设计?面试......