自学内容网 自学内容网

React面试题笔记(一)

一、react基础面试题

1.react中keys的作用是什么?

key是是用于追踪哪些列表被修改,被添加或者被移除的辅助标识。

在开发过程中,我们需要保证某个元素的 key 在其同级元素中具有唯一性。在 React Diff 算法中 React 会借助元素的 Key 值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系,因此我们绝不可忽视转换函数中 Key 的重要性。

2.react中refs的作用是什么?

class组件中:

Refs 是 React 提供给我们的安全访问 DOM 元素或者某个组件实例的句柄。我们可以为元素添加 ref 属性然后在回调函数中接受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回:

class CustomForm extends Component {
  handleSubmit = () => {
    console.log("Input Value: ", this.input.value)
  }
  render () {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type='text'
          ref={(input) => this.input = input} />
        <button type='submit'>Submit</button>
      </form>
    )
  }
}

function组件中:

函数式组件同样能够利用闭包暂存其值:

function CustomForm ({handleSubmit}) {
  let inputElement = useRef({})
  return (
    <form onSubmit={() => handleSubmit(inputElement.current.value)}>
      <input
        type='text'
        ref={inputElement} />
      <button type='submit'>Submit</button>
    </form>
  )
}

3.react中三种构建组件的方式?

1)React.createClass():很少使用

2)ES6 class:class组件

3)无状态函数:多指的是函数组件

4.调用setstate之后发生了什么?

1)状态合并:

在代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。

2)构建渲染react树:

经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。

3)diff节点差异:

在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。

4)按需更新:

在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

5.react diff原理

1)把树形结构按照层级分解,只比较同级元素

2)列表添加唯一key

3)只匹配相同class的component(这里面的class指的是组件的名字)

4)合并,调用setstate方法的时候,react将其标记为dirty,到每一个事件循环结束,react检查标记dirty的component重新绘制。

5)选择性子树渲染,开发人员可以重写shouldComponentUpdate提高diff的性能(function组件useMemo加memo提高性能)

6.为什么传递给setState的参数是一个callback而不是一个对象?

因为 this.props 和 this.state 的更新可能是异步的,不能依赖它们的值去计算下一个 state。

7.除了在构造函数中绑定this,还有其他方式吗?

你可以使用属性初始值设定项(property initializers)来正确绑定回调,create-react-app 也是默认支持的。在回调中你可以使用箭头函数,但问题是每次组件渲染时都会创建一个新的回调。

8.setState第二个参数的作用

因为setState是一个异步的过程,所以说执行完setState之后不能立刻更改state里面的值。如果需要对state数据更改监听,setState提供第二个参数,就是用来监听state里面数据的更改,当数据更改完成,调用回调函数

9.(在构造函数中)调用super(props)的目的是什么?

1)在 super() 被调用之前,子类是不能使用 this 的。

2)子类必须在 constructor 中调用 super()。

3)传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props。

10.简述flux思想

最大特点,就是数据的"单向流动"。

1)用户访问connect封装的组件 View
2)View 发出用户的 Action
3)Dispatcher 收到 Action,要求 Store 调用reducer对state进行相应的更新
4)Store 更新后,发出一个"change"事件
5)View 收到"change"事件后,根据更新的state刷新页面

11.在React中Element和Component的区别?

1)一个 React element 描述了你想在屏幕上看到什么。

换个说法就是,一个 React element 是一些 UI 的对象表示。

2)一个 React Component 是一个函数或一个类,它可以接受输入并返回一个 React element t(通常是通过 JSX ,它被转化成一个 createElement 调用)。

12.描述事件在React中的处理方式?

1)为了解决跨浏览器兼容性问题,您的 React 中的事件处理程序将传递 SyntheticEvent 的实例,它是 React 的浏览器本机事件的跨浏览器包装器。

2)这些 SyntheticEvent 与您习惯的原生事件具有相同的接口,除了它们在所有浏览器中都兼容。

3)有趣的是,React 实际上并没有将事件附加到子节点本身。React 将使用单个事件监听器监听顶层的所有事件。这对于性能是有好处的,这也意味着在更新 DOM 时,React 不需要担心跟踪事件监听器。

13.createElement和cloneElement有什么区别?

createElement:

1)React.createElement():JSX 语法就是用 React.createElement()来构建 React 元素的。

2)它接受三个参数,第一个参数可以是一个标签名。如 div、span,或者 React 组件。第二个参数为传入的属性。第三个以及之后的参数,皆作为组件的子组件。

React.createElement(
    type,
    [props],
    [...children]
)

cloneElement:

1)React.cloneElement()与 React.createElement()相似。

2)不同的是它传入的第一个参数是一个 React 元素,而不是标签名或组件。

3)新添加的属性会并入原有的属性,传入到返回的新元素中,而就的子元素奖杯替换。

React.cloneElement(
  element,
  [props],
  [...children]
)

14.如何告诉react它应该编译产生环境版本?

1)通常情况下我们会使用 Webpack 的 DefinePlugin 方法来将 NODE_ENV 变量值设置为 production。

2)编译版本中 React 会忽略 propType 验证以及其他的告警信息,同时还会降低代码库的大小,React 使用了 Uglify 插件来移除生产环境下不必要的注释等信息。

15.Controlled Component和Uncontrolled Component之间的区别是什么?

1)受控组件(Controlled Component):

代指那些交由 React 控制并且所有的数据统一存放的组件。

2)非受控组件(Uncontrolled Component):

则是由DOM存放表单数据,并非存放在 React 组件中。我们可以使用 refs 来操控DOM元素

注意:

不过实际开发中我们并不提倡使用非受控组件,因为实际情况下我们需要更多的考虑表单验证、选择性的开启或者关闭按钮点击、强制输入格式等功能支持,而此时我们将数据托管到 React 中有助于我们更好地以声明式的方式完成这些功能。引入 React 或者其他 MVVM 框架最初的原因就是为了将我们从繁重的直接操作 DOM 中解放出来。

二、React组件面试题

1.展示组件和容器组件有何不同?

1.1展示组件:

关心组件看起来是什么。展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态。


1.2容器组件:

1)更关心组件是如何运作的。

2)容器组件会为展示组件或者其它容器组件提供数据和行为(behavior),它们会调用 Flux actions,并将其作为回调提供给展示组件。

3)容器组件经常是有状态的,因为它们是(其它组件的)数据源。

 2.类组件和函数组件有何不同?

1)类组件不仅允许你使用更多额外的功能,如组件自身的状态和生命周期钩子,也能使组件直接访问 store 并维持状态
2)当组件仅是接收 props,并将组件自身渲染到页面时,该组件就是一个 '无状态组件(stateless component)',可以使用一个纯函数来创建这样的组件。这种组件也被称为哑组件(dumb components)或展示组件

 3.(组件的)状态(state)和属性(props)之间有何不同?

1)State :

是一种数据结构,用于组件挂载时所需数据的默认值。State 可能会随着时间的推移而发生突变,但多数时候是作为用户事件行为的结果。


2)Props(properties 的简写):

则是组件的配置。props 由父组件传递给子组件,并且就子组件而言,props 是不可变的(immutable)。组件不能改变自身的 props,但是可以把其子组件的 props 放在一起(统一管理)。Props 也不仅仅是数据--回调函数也可以通过 props 传递。

4.何为受控组件?

 [state,setState]=useState(),比如输入框,它的值通过 React 的这种方式来控制,这样的元素就被称为"受控元素"。

5.何为高阶组件?

1)高阶组件是一个以组件为参数并返回一个新组件的函数。

2)HOC 运行你重用代码、逻辑和引导抽象。

3)最常见的可能是 Redux 的 connect 函数。

4)除了简单分享工具库和简单的组合,HOC 最好的方式是共享 React 组件之间的行为。

如果你发现你在不同的地方写了大量代码来做同一件事时,就应该考虑将代码重构为可重用的 HOC。

 6.应该在React组件的何处发起ajax请求?

1)在 React 组件中,应该在 componentDidMount 中发起网络请求。

2)这个方法会在组件第一次“挂载”(被添加到 DOM)时执行,在组件的生命周期中仅会执行一次。

 7.React中组件传值?

1)父传子(组件嵌套浅):父组件定义一个属性,子组件通过this.props接收。
2)子传父:父组件定义一个属性,并将一个回调函数赋值给定义的属性,然后子组件进行调用传过来的函数,并将参数传进去,在父组件的回调函数中即可获得子组件传过来的值。

3)父获取子组件的数据和方法:父组件传递ref给Child组件;forwardRef封装子组件,使用useImperativeHandle钩子保留数据和方法给父组件使用:

import React, { forwardRef, useImperativeHandle } from 'react';
 
// 子组件
const ChildComponent = forwardRef((props, ref) => {
  // 使用 useImperativeHandle 自定义公开的方法
  useImperativeHandle(ref, () => ({
    getValue: () => props.value
  }));
 
  return <input type="text" {...props} />;
});
 
// 父组件
const ParentComponent = () => {
  const childRef = useRef(null);
 
  const handleClick = () => {
    if (childRef.current) {
      alert(childRef.current.getValue());
    }
  };
 
  return (
    <>
      <ChildComponent ref={childRef} value="我是Child组件的值" />
      <button onClick={handleClick}>获取Child值</button>
    </>
  );
};

 8.什么时候在功能组件上使用类组件?

如果您的组件具有状态( state )或生命周期方法,请使用 Class 组件。否则,使用功能组件

 9.受控组件和非受控组件有什么区别?

受控组件:

1)数据驱动,使用state状态渲染组件

非受控组件:

1)不受控制( uncontrolled component )的组件是您的表单数据由 DOM 处理,而不是您的 React 组件。我们使用 refs 来完成这个。

10.React组件的划分业务组件技术组件?

根据组件的职责通常把组件分为 UI 组件和容器组件。
1)UI 组件负责 UI 的呈现;

2)容器组件负责管理数据和逻辑。
3)两者通过 React-Redux 提供 connect 方法联系起来。

三、redux面试题

1.redux中间件

1)中间件提供第三方插件的模式,自定义拦截action->reducer的过程。

2)变为action->middlewares->reducer。

3)这种机制可以让我们改变数据流,实现异步action,action过滤,日志输出,异常报告等功能。

常见的中间件:

redux-logger:提供日志输出

redux-thunk:处理异步操作

redux-promise:处理异步操作,actionCreator的返回值是Promise

2.redux有什么缺点?

1)一个组件所需要的数据,必须由父组件传过来,而不能像redux中直接从store取。

2)当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新render,可能会有效率影响,或者需要写复杂的shouldComponentUpdate进行判断。

3.说一下你理解的redux?

概念:

redux 是一个应用数据流框架,主要是解决了组件间状态共享的问题,原理是集中式管理。

主要有三个核心方法,action,store,reducer。

redux的工作流程:

工作流程是 view 调用 store 的 dispatch 接收 action 传入 store,reducer 进行 state 操作,view 通过 store 提供的 getState 获取最新的数据。

flux的工作流程:

flux 也是用来进行数据操作的,有四个组成部分 action,dispatch,view,store,工作流程是 view 发出一个 action,派发器接收 action,让 store 进行数据更新,更新完成以后 store 发出 change,view 接受 change 更新视图。

redux和flux的区别:

1)主要区别在于 Flux 有多个可以改变应用状态的 store,在 Flux 中 dispatcher 被用来传递数据到注册的回调事件,但是在 redux 中只能定义一个可更新状态的 store,redux 把 store 和 Dispatcher 合并,结构更加简单清晰。
2)新增 state,对状态的管理更加明确,通过 redux,流程更加规范了,减少手动编码量,提高了编码效率,同时缺点时当数据更新时有时候组件不需要,但是也要重新绘制,有些影响效率。一般情况下,我们在构建多交互,多数据流的复杂项目应用时才会使用它们

四、React性能比较面试题

1.vue和react的区别?

1)react严格上针对的是mvc模式的view层,vue则是mvvm模式。
2)操作dom的方式不同,vue使用的是指令操作dom,react是通过js进行操作。
3)数据绑定不同,vue实现的是双向绑定,react的数据流动是单向的。
4)react中state是不能直接改变的,需要使用setState改变。vue中的state不是必须的,数据主要是由data属性在vue对象中管理的。

2.react性能优化的方案

(1)重写shouldComponentUpdate来避免不必要的dom操作。

注意:function组件使用useMemo+memo结合优化性能,它们可以避免组件或组件内部的计算在每次渲染时都执行,从而减少不必要的性能开销。
(2)使用 production 版本的react.js。
(3)使用key来帮助React识别列表中所有子组件的最小变化。

3.react项目用过什么脚手架

Mern:MERN是脚手架的工具,它可以很容易地使用Mongo, Express, React and NodeJS生成同构JS应用。它最大限度地减少安装时间,并得到您使用的成熟技术来加速开发。

webpack:单独开文章写笔记

vite:单独开文章写笔记

gulp:。。。

4.介绍一下webpack

webpack是一个前端模块化打包工具,主要由入口,出口,loader,plugins四部分组成。

前端打包工具还有一个gulp,侧重前端开发的过程,而webpack侧重于模块,例如它会把css文件看作一个模块,通过css-loader将css打包成符合css的静态资源。

5.如果你创建了类似于下面的Twitter元素,那么它们相关的类定义是什么?

<Twitter username='tylermcginnis33'>
  {(user) => user === null
    ? <Loading />
    : <Badge info={user} />}
</Twitter>

这种模式中,组件会接收某个函数作为其子组件,然后在渲染函数中以 props.children 进行调用:

import React, { Component, PropTypes } from 'react'
import fetchUser from 'twitter'
class Twitter extends Component {
  state = {
    user: null,
  }
  static propTypes = {
    username: PropTypes.string.isRequired,
  }
  componentDidMount () {
    fetchUser(this.props.username)
      .then((user) => this.setState({user}))
  }
  render () {
    return this.props.children(this.state.user)
  }
}

这种模式的优势在于将父组件与子组件解耦和,父组件可以直接访问子组件的内部状态而不需要再通过 Props 传递,这样父组件能够更为方便地控制子组件展示的 UI 界面。譬如产品经理让我们将原本展示的 Badge 替换为 Profile,我们可以轻易地修改下回调函数即可:

<Twitter username='tylermcginnis33'>
  {(user) => user === null
    ? <Loading />
    : <Profile info={user} />}
</Twitter>

6.为什么我们需要使用react提供的children API而不是Javascript的map?

props.children并不一定是数组类型,譬如下面这个元素:

<Parent>
  <h1>Welcome.</h1>
</Parent>

如果我们使用props.children.map函数来遍历时会受到异常提示,因为在这种情况下props.children是对象(object)而不是数组(array)。
React 当且仅当超过一个子元素的情况下会将props.children设置为数组,就像下面这个代码片:

<Parent>
  <h1>Welcome.</h1>
  <h2>props.children will now be an array</h2>
</Parent>

这也就是我们优先选择使用React.Children.map函数的原因,其已经将props.children不同类型的情况考虑在内了。

createElement 函数是 JSX 编译之后使用的创建 React Element 的函数,而 cloneElement 则是用于复制某个元素并传入新的 Props。

 四、React常见的几种钩子

1.useState

1、useState 是用来解决函数组件中不能定义自己的状态的问题,useState 可以传递一个参数,做为状态的初始值,返回一个数组,数组的第一个元素是返回的状态变量,第二个是修改状态变量的函数

他的定义格式,第一个是变量名,第二个是改变变量的方法

const [state, setState] = useState(initalState); // 初始化,state可以任意命名

setState(newState); // 修改state的值

2.useEffect

useEffect  在类组件中放在 componentDidMount,componentDidUpdate 等执行的请求获取数据的操作,在React Hooks中都可以用 useEffect 来处理,他可以类比类组件中的两个生命周期函数。

useEffect(() => {
  // 此处编写 组件挂载之后和组件重新渲染之后执行的代码
  ...
 
  return () => {
    // 此处编写 组件即将被卸载前执行的代码
    ...
  }
}, [dep1, dep2 ...]); // 依赖数组

 useEffect和useLayoutEffect的区别?

1)执行时机不同


useEffect:在组件渲染到屏幕之后异步执行。这意味着它不会阻塞浏览器的绘制和更新,适用于大多数与数据获取、订阅事件、手动修改DOM等不会直接影响页面布局和视觉呈现的操作。
useLayoutEffect:会在浏览器进行布局和绘制之前同步执行。useLayoutEffect中执行的操作会修改DOM样式或结构,并且在浏览器绘制之前就完成这些修改,避免页面的重绘和回流带来的性能问题。
注意:useLayoutEffect是在DOM结构更新后、渲染前执行,在渲染时是同步执行,相当于有一个防抖效果。

2)对性能影响不同


useEffect:由于是异步执行,不会阻塞页面的渲染,对用户交互的响应性影响较小,但如果副作用操作耗时较长,可能会在用户操作后有短暂的延迟才看到效果。
useLayoutEffect:由于是同步执行,如果在其中执行的操作耗时较长,会阻塞页面的渲染,可能导致页面卡顿,影响用户体验。


3)对渲染的影响不同:


useEffect 的执行不会阻塞浏览器的渲染工作
useLayoutEffect 的执行可能会阻塞浏览器的渲染,使用 useLayoutEffect 时需要注意性能问题。


4) 使用场景不同


一般情况下,如果副作用操作不会影响页面的布局,建议使用useEffect。例如发送网络请求获取数据、添加事件监听器、更新本地存储等。
如果副作用操作会影响页面的布局和视觉呈现,例如直接修改DOM元素的样式、位置、大小等,为了避免页面的闪烁和重绘,建议用useLayoutEffect。
useLayoutEffect会在浏览器进行布局和绘制之前同步执行。这意味着它可以在 DOM 更新后、浏览器绘制之前进行操作,从而避免由于异步的useEffect可能导致的闪烁现象。

使用建议:


将直接影响页面布局和视觉呈现的操作放在useLayoutEffect中,例如直接修改 DOM 元素的样式、位置、大小等。因为它会等待这些操作完成后再进行渲染,所以可以避免页面的闪烁。
减少useLayoutEffect中执行的复杂或耗时操作。由于它是同步执行,如果操作过于耗时,可能会阻塞页面的渲染,导致卡顿。如果必须进行复杂计算或耗时操作,可以考虑将其拆分为异步操作,或者在操作完成后再进行必要的 DOM 更新。
精确管理依赖项,只将会影响布局的变量添加到依赖项数组中。这样可以避免不必要的useLayoutEffect执行。

 3.useLayoutEffect

useLayoutEffect 使用方法、所传参数和 useEffect 完全相同。大多数情况下将 useEffect 替换成 useLayoutEffect 完全看不出区别。


唯一区别就是:

使用 useEffect 时,页面挂载会出现闪烁。而使用 useLayoutEffect 时页面没有闪烁,是因为 useEffect 是在页面渲染完成后再去更新数据的,所以会出现短暂的闪烁,而 useLayoutEffect 是在页面还没有渲染时就将数据给更新了,所以没有出现闪烁。


注意:大部分情况用useEffect就足够了,useLayoutEffect 会阻塞渲染,所以需要小心的使用。

 4.useMemo

useMemo 是为了减少组件重新渲染时不必要的函数计算,可以用来做性能优化。

类似于vue中的计算属性,他的依赖值是后面数组中的值

const memoizedValue = useMemo(() => {
  // 计算逻辑
  ...
  // return res;
}, [a, b]);
useMemo 可以传入2个参数,第1个参数为函数,用来进行一些计算,第2个参数是依赖关系(可选参数),返回值为第一个函数 return 出去的值,只有在依赖项发生变化时才会重新执行计算函数进行计算,如果不传依赖项,每次组件渲染都会重新进行计算。

// 代码示例
import { useState, useMemo } from 'react'
 
function Demo() {
    const [num, setNum] = useState(0);
 
 
    const addNum = () => {
        setNum(num + 100);
    };
 
    const total = useMemo(() => {
        console.log('---求和---');
        // 求和计算
        let temp = 0;
        for(let i = num; i > 0; i--) {
            temp += i;
        }
        return temp;
    }, [num]);
 
    return (
        <div>
            <button onClick={addNum}>addNum</button>
            <p>{`num: ${num}`}</p>
            <p>{`total: ${total}`}</p>
        </div>
    )
}
 
export default Demo;

点击修改num的值,total 对应的计算函数会重新执行一遍,因为num是该计算函数的依赖项

5.useContext

在 React 中传递属性只能一层一层传,如果组件结构比较复杂,层级比较深的时候,数据传递起来就比较麻烦,可能会经过很多次的传递才能将属性传递到目标组件中,那么有没有一种可以在全局进行状态共享的实现方法呢?useContext 就是为了解决这个问题的,可以实现不必层层传递就能共享状态的功能。具体用法看下面步骤:

先封装一个js,里面可以设置初始值,这个初始值,可以在任何地方使用

import React from 'react';
// React.createContext()中的参数是默认值,可填可不填
const UserContext = React.createContext( { name: '张三' });
export default UserContext;


在代码中引用封装好的js文件

Father:

import React, { useContext } from 'react'
import UserContext from './context';
 
// const UserContext = React.createContext();
 
function Demo() {
    // 如果React.createContext没有指定默认值,也可以在对应子组件上套上UserContext.Provider来指定值
    return (
        // <UserContext.Provider value={{ name: '张三' }}>
            <Child />
        // </UserContext.Provider>
    )
}


 
 Child:

function Child() {
 
    const user = useContext(UserContext);
    return (
        <div>
            <p>{`name: ${user.name}`}</p>
        </div>
    )
}
 
export default Demo;

 6.useReducer

useReducer 也是用来实现状态管理的 hook,useState 就是基于 useReducer 实现的,useReducer 可以实现比 useState 更复杂的状态管理逻辑。

它可以对多个值进行管理,他的定义方式和useState很像,但是,useState 是基于它实现的,使用时注意定义的参数

// 代码示例
import React, { useReducer } from 'react'
 
// 1.需要有一个 reducer 函数,第一个参数为之前的状态,第二个参数为行为信息
function reducer(state, action) {
    switch (action) {
        case 'add':
            return state + 1;
        case 'minus':
            return state - 1;
        default:
            return 0;
    }
}
 
 
 
function Demo() {
 
    // 2.引入useReducer,第一个参数时上面定义的reducer,第二个参数时初始值
    // 3.返回为一个数组,第一项为状态值,第二项为一个 dispatch 函数,用来修改状态值
    const [count, dispatch] = useReducer(reducer, 0);
    return (
        <div>
            <button onClick={() => { dispatch('add') }} >add</button>
            <button onClick={() => { dispatch('minus') }} >minus</button>
            <button onClick={() => { dispatch('unknown') }} >unknown</button>
            <p>{`count: ${count}`}</p>
        </div>
    );
}
 
export default Demo;

7.useRef

useRef 可以帮助我们获取 dom 和 react 组件实例,类组件中的 React.createRef() 也有相同的功能。

除了用 useRef 获取组件实例,还可以用来存储变量的值,但是需要注意的一点是,修改 .current 的值不会触发组件的重新渲染。

8.useCallback

返回一个缓存的回调函数,缓存一个函数类型因变量

useCallback和useMemo的区别:

useCallback 的用法和 useMemo 完全一样,useMemo 返回的是计算函数 return 出去的,而 useCallback 可以理解成返回的是那个计算函数

9.React.memo

当父组件发生改变时,默认情况下它的子孙组件也会重新渲染,当某些子组件不需要更新时,也会被强制更新,为了避免这种情况,我们可以使用 React.memo。
类组件中有 shouldComponentUpdate 和 PureComponent 来避免子组件做不必要的渲染。

函数组件中的 React.memo() 也有类似的功能,它和 PureComponent 类似,但是只适用于函数组件,默认情况下仅对 props 进行一个浅比较来决定要不要更新,复杂情况下支持自己手写对比的逻辑。

function Demo(props) {
  // ...
}
 
function compare(prevProps, nextProps) {
  // 自己写对比逻辑,返回 true 更新,false 跳过更新
  // return false
}
 
export default React.memo(Demo, compare)
  • 参数1:组件要渲染的内容。
  • 参数2:写的回调函数,一般情况下都在props传过来的数据为引用类型,才需要手动来判断,如果是基本类型则不需要写参数2来手动判断。

如果是引用类型,可以用下面方法进行比较 

const Child = React.memo(
    ({ count }) => {
        return (
            <div>
                <h3>child组件 -- {count.n}</h3>
            </div>
        )
    },
    // 使用lodash库来完成对象的值的比较,从而用来完成减少组件的无用的重复渲染
    (prevProps, nextProps) => _.isEqual(prevProps, nextProps)
)

10.forwardRef

forwardRef 可以在父组件中操作子组件的 ref 对象,并且将 ref 对象作为一个参数传递给了子组件。

forwardRef可以结合useImperativeHandle钩子使用,暴露值和方法给父组件使用。

加上forwardRef后子组件就多了个入参ref,来绑定对应子组件的dom元素。

11.总结:

可以将他们分为两个部分(其中useRef 不属于两者):

11.1自变量:本身是可以改变从而影响其他

1) useState 定义自变量

2) useReducer 用于操作多个自变量(一个层级的自变量和因变量也可以成为其他层级的自变量和因变量)

3) useContext 可以跨层级的传递自变量

11.2 因变量:因自变量改变而导致自己改变

1) useMemo 和 useCallback(缓存函数类型因变量) 定义无副作用的因变量

 2) useEffect 定义有副作用(可以进行一些操作,比如修改某些参数,请求数据,操作dom等)的因变量

3) useReducer 可看成是一个进阶版的useState ,借用redux的设计理念,将多个state合并成一个,本质上也是一个因变量。

4) useRef 可以操作子组件中的方法,也可以作为一个保存数值的标记,在路径中起到缓存数据的作用

更多可见文档地址:

https://zh-hans.react.dev/reference/react/hooks

五、高级指引:

1.无障碍

2.代码分割

3.Context

4.错误边界

5.Refs转发

6.Fragments

7.高阶组件

8.与第三方组件协同

9.深入jsx

10.性能优化

11.Portals

12.Profiler

13.不使用es6

14.不使用jsx

15.协调

16.Refs&DOM

17.Render Props

18.静态类型检查

19.严格模式

20.使用propTypes类型检查

21.非受控组件

22.Web Components

更多可参考文档地址:

https://zh-hans.react.dev/reference/react


原文地址:https://blog.csdn.net/qq_42750608/article/details/142891690

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!