ToB企服应用市场:ToB评测及商务社交产业平台

标题: React:组件、状态与变乱处置惩罚的完整指南 [打印本页]

作者: 小小小幸运    时间: 2024-12-23 14:23
标题: React:组件、状态与变乱处置惩罚的完整指南
JSX

     JSX 出现的原因

     JSX 出现的主要原因是为了解决 React 中组件渲染的题目。在 React 中,用户界面是由组件构造的,而每个组件都可以看作是一个函数。这些组件或函数需要返回一些需要渲染的内容,而这些内容通常是 HTML 元素。
     在早期的 JavaScript 中,如果要创建和操作HTML元素,需要使用一些相对较为复杂的 DOM API,这对开辟者来说可能并不友好。而 JSX 就是一个 JavaScript 的语法扩展,它使得我们可以在 JavaScript 中直接写HTML(或者说看起来很像HTML)的语法,极大地进步了开辟效率,也使得代码更加易读和易维护。
     因此,JSX 的出现使得 React 的组件化开辟变得更加简单和直观。通过JSX,开辟者可以更加专注于组件的逻辑,而不是DOM操作,从而进步开辟效率。
     React 的一大亮点就是虚拟 DOM:可以在内存中创建虚拟 DOM 元素,由虚拟 DOM 来确保只对界面上真正变化的部分进行实际的 DOM 操作。和真实 DOM 一样,虚拟 DOM 也可以通过 JavaScript 来创建:
                                   登录后复制                        
  1. const ele = React.createElement('div', null, 'hello, world')
复制代码
      
                       虽然通过以上的方式,就可以构建成 DOM 树,但这种代码可读性比力差,于是就有了 JSX 。JSX 是 JavaScript 的语法扩展,使用 JSX ,就可以接纳我们熟悉的 HTML 标签情势来创建虚拟 DOM,也可以说 JSX 是 React.createElement 的一个语法糖
                                   登录后复制                        
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>react</title>
  7. </head>
  8. <body>
  9.     <div id="app"></div>
  10.     <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  11.     <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
  12.     <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>
  13.     <script type="text/babel">
  14.         const container = document.getElementById('app');
  15.         const root = ReactDOM.createRoot(container);
  16.         root.render(<h1>Hello, world</h1>);
  17.     </script>
  18. </body>
  19. </html>
复制代码
      
                       

     什么是JSX

     JSX(JavaScript XML),即在 JavaScript 语言里加入类 XML 的语法扩展。在 React 中,JSX 是一种 JavaScript 的语法扩展。它看起来很像 HTML,允许你在 JavaScript 中直接写 HTML 代码。JSX 能进步代码的可读性,使得你的代码更加直观和易于维护。实际上,JSX 只是提供了一种创建 React 元素的语法糖,它最终会被转换到普通的 JavaScript 函数调用和对象。因此,JSX 既是 React 的一个紧张特性,也是编写 React 应用的一种推荐方式。有不少初学者对 React 的第一印象就是 JSX 语法,以至于会有这样的误解:
     
     总的来说,React 是一套声明式的、组件化的前端框架。顾名思义,声明组件是 React 前端开辟工作最紧张的组成部分。在声明组件的代码中使用了 JSX 语法,JSX 并非 HTML,它也并不代表组件的全部内容。
     如何使用JSX

     
                                   登录后复制                        
  1. // HTML 类型标签
  2. const ele = <div>hello, world</div>
  3. // react 组件类型标签
  4. const component = <HelloWrold />
复制代码
      
                       在 JSX 语法中,有两种标签范例:
     
     React 通过标签首字母的大小写来区分渲染的是标签范例。React 中的所有标签,都必须有闭合标签 />
     
                                   登录后复制                        
  1. // 属性传值
  2. const addUser = {id: 1, name: '添加好友'}
  3. <PanelItem item={addUser} />
复制代码
      
                                                     登录后复制                        
  1. // 通过表达式定义子组件
  2. const teams = [
  3.   {id: 1, name: '创建高级群'},
  4.   {id: 2, name: '搜索高级群'}
  5. ]
  6. <ul>
  7.   {teams.map(item =>
  8.       <PanelItem
  9.         item={item}
  10.         key={item.id}/>
  11.   )}
  12. </ul>
复制代码
      
                             JSX 中使用 JavaScript 表达式时,不能使用多行 JavaScript 语句。
          JSX 的规则

     
     JSX 元素范例

     SX 产生的每个节点都称作 React 元素,它是 React 应用的最小单元;React 元素有四种基本范例:
     
     JSX 的属性设置

     React 对 DOM 元素的封装实际上是对整个浏览器 DOM 的一次 React 化标准化。比方,HTML 中轻易引发肴杂的 readonly="true",其W3C标准应为 readonly="readonly",而常被误用的 readonly="false" 实际上没有用果。但在 React 的 JSX 中,这就统一为 readOnly={true} 或 readOnly={false},这更接近JS的开辟习惯。而对于样式中的 className="container",主要是因为 HTML 标签中的 class 是 JS 的保留字,以是需要避免使用。
     在 React 组件渲染的元素中,JSX 的 props 应与自界说组件界说中的 props 相对应;如果没有特殊处置惩罚,那些没有对应 props 的元素会被忽略。这也是开辟 JSX 时常会遇到的一个错误,那就是在组件界说中更改了 props 的属性名,但忘记了更改对应的 JSX 元素中的 props,导致子组件无法获取属性值。对于 Fragment 元素,它是没有 props 的。
     JSX 子元素范例

     JSX元素可以界说子元素。这里有一个紧张的概念要明白:并非所有子元素都是子组件,但所有子组件肯定都是子元素
     子元素的范例包括:
     
                                   登录后复制                        
  1. <div>Hello World!</div>
复制代码
      
                       
                                   登录后复制                        
  1. <div><p>Hello World!</p></div>
复制代码
      
                       
                                   登录后复制                        
  1. <div>{1+2}</div> // 渲染结果为:3
复制代码
      
                       
                                   登录后复制                        
  1. <div>{null}</div> // 不会渲染任何内容
  2. <div>{undefined}</div> // 不会渲染任何内容
  3. <div>{false}</div> // 不会渲染任何内容
复制代码
      
                       
                                   登录后复制                        
  1. <div>
  2.   {['Hello', <p>World</p>, 1+2, null, undefined, false]}
  3. </div>
复制代码
      
                       以上代码会渲染出 "Hello",一个包罗 "World" 的段落元素,以及数字3。null、undefined 和 false 不会被渲染。
     JSX 中的 JS 表达式

     在JSX中,我们可以嵌入JavaScript表达式,这些表达式被大括号 { } 包围。这主要在两个方面被应用:
     
                                   登录后复制                        
  1. let myClass = "my-css-class";
  2. <div className={myClass}></div>
复制代码
      
                       在这个例子中,我们界说了一个变量myClass,并用大括号把它作为className属性的值。
     
                                   登录后复制                        
  1. let text = "Hello, JSX!";
  2. <div>{text}</div>
复制代码
      
                       在这个例子中,我们界说了一个变量text,并用大括号把它作为div元素的子元素。
     JSX是声明性的,因此其内部不应包罗命令式的语句,比方 if ... else ...。当你不确定JSX { } 里的代码是否是表达式时,你可以实行将这部分代码直接赋值给一个JS变量。如果赋值乐成,那么它就是一个表达式;如果赋值失败,那么你可以从以下四个方面进行查抄:
     
     有个 props 表达式的特殊用法: 睁开语法,<Button {...defaultProps}> 利用的 JavaScript 中的睁开语法把 defaultProps 这个对象的所有属性都传给 Button 这个组件。
     JSX 中使用解释

     如果你实行在JSX中使用HTML的解释方法,你会发现它无法通过编译。因此,你需要使用 {/ 这是解释 /} 的格式来添加解释。在编译过程中,这种格式的解释会自动被识别为JS解释。
                                   登录后复制                        
  1. const App = () => {
  2.     const handleClick = () => {
  3.         console.log('click');
  4.     };
  5.     return (
  6.         <div>
  7.             {/* 这个是注释 */}
  8.             <button onClick={handleClick}>click me</button>
  9.         </div>
  10.     );
  11. };
  12. export default App;
复制代码
      
                       React 中的组件

     在我们已经初步明白了JSX的底子上,接下来我们将探究什么是组件,以及JSX与React组件的关系是什么。
组件化开辟现已经成为前端开辟的主流方法,险些所有的前端框架都包罗了组件的概念。在一些框架中,它被称为"Component",而在其他一些中则被称为"Widget"。然而在React中,组件被视为前端应用的焦点。
     什么是 react 组件

     组件是对视图以及与视图干系的逻辑、数据、交互等的封装。如果没有组件这层封装,这些代码将有可能四散在各个地方,低内聚,也不肯定能低耦合,这种代码每每难写、难读、难维护、难扩展。
     React 组件条理布局从一个根部组件开始,一层层加入子组件,最终形成一棵组件树。
     

     这棵树由节点组成,每个节点代表一个组件。比方,App、FancyText、Copyright 等都是树中的节点。
     在 React 渲染树中,根节点是应用程序的 根组件。在这种环境下,根组件是 App,它是 React 渲染的第一个组件。树中的每个箭头从父组件指向子组件。
     JSX 与 React 组件的关系

     JSX就是React组件的语法糖,它让我们可以使用类似于HTML的语法来界说React组件。在React中,我们通常使用JSX来描述组件的UI布局。当我们编写JSX代码时,实际上我们是在界说React组件的渲染输出。
     比方,我们可以界说一个名为"HelloWorld"的React组件,使用JSX来描述它的UI:
                                   登录后复制                        
  1. function HelloWorld() {
  2.   return <h1>Hello, world!</h1>;
  3. }
复制代码
      
                       在上述代码中,<h1>Hello, world!</h1> 就是 JSX。当 React 渲染这个HelloWorld 组件时,它会将 JSX 转换为相应的 HTML,然后将其插入到 DOM 中。
     组件的范例

     组件化开辟已经成为前端开辟的主流趋势,市面上大部分前端框架都包罗组件概念,有些框架里叫 Component,有些叫 Widget。在React框架中,主要有两种范例的组件:类组件和函数组件。类组件通常用于需要内部状态或生命周期方法的复杂环境,而函数组件则适用于无状态的、更简单的环境。但是从React 16.8版本开始,借助React Hooks,函数组件也可以拥有状态和生命周期方法。
     每种组件范例都有其上风和适用场景,明白它们的作用和差别是成为一名高效的开辟者的关键。
     类组件

     在React中,类组件是一种可以包罗状态和生命周期方法的组件范例。类组件是ES6的类,它们继承自 React.Component 或 React.PureComponent。
     要界说一个 React 类组件,你需要扩展内置的 Component 类并界说一个 render() 方法。React 会在需要确定屏幕上显示什么内容时调用你的 render 方法。
     比方:
                                   登录后复制                        
  1. import { Component } from 'react';
  2. //类组件是由继承与React的Component基类构建
  3. class Greeting extends Component {
  4.     render() {
  5.         return <h1>Greeting, friend! How are you today?</h1>;
  6.     }
  7. }
复制代码
      
                       类组件在界说是,同样可以使用属性:
                                   登录后复制                        
  1. import { Component } from 'react';
  2. class Greeting extends Component {
  3.     render() {
  4.         return <h1>Greeting, {this.props.name}!</h1>;
  5.     }
  6. }
复制代码
      
                       在类组件中,通过 this 对象访问其自身 props 属性对象。
     通过类组件构造 React 元素时,也可以为其指定属性赋值:
                                   登录后复制                        
  1. function App() {
  2.     return (
  3.         <div className="App">
  4.             <header className="App-header">
  5.                 <p>hello world!!!</p>
  6.             </header>
  7.             <Greeting name="Newton" />
  8.         </div>
  9.     );
  10. }
复制代码
      
                       完整代码如下( github 中检察源码):
                                   登录后复制                        
  1. import { Component } from 'react';import './App.css';class Greeting extends Component {    render() {        return <h1>Greeting, {this.props.name}!</h1>;    }}function App() {
  2.     return (
  3.         <div className="App">
  4.             <header className="App-header">
  5.                 <p>hello world!!!</p>
  6.             </header>
  7.             <Greeting name="Newton" />
  8.         </div>
  9.     );
  10. }export default App;
复制代码
      
                       运行效果如下:
     

     类组件还可以跟踪它们的状态(state),并使用状态更新来触发重新渲染。这使得类组件非常得当用于需要内部状态管理的复杂组件。
     函数组件

     将 UI 拆分成独立的、可复用的代码片段,并对每个代码片段进行单独处置惩罚。在 React 中,有两类常用的组件:函数组件(也叫无状态组件)和类组件(也叫 class 组件);然而,目前 React 官方以及社区的发展趋势,已经开始更多地推荐和支持使用函数组件,而不是类组件。因此,我们接下来的学习和探索,将主要围绕函数组件进行。
     React 组件是一段可以使用标签进行扩展 的 JavaScript 函数。如下所示(你可以编辑下面的示例):
                                   登录后复制                        
  1. function Profile() {
  2.     return (
  3.         <img
  4.             src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/39/GodfreyKneller-IsaacNewton-1689.jpg/250px-GodfreyKneller-IsaacNewton-1689.jpg"
  5.             alt="Katherine Johnson"
  6.         />
  7.     );
  8. }
复制代码
      
                       函数组件在某些方面可以替代类组件,它们的语法更为简洁明白。然而,函数组件面临着两个主要的挑战:
     
     这两个题目在某些环境下可能会限定函数组件的使用。但值得注意的是,自从 React 16.8 引入 Hooks 功能后,函数组件现在也可以拥有状态和生命周期方法,这大大增强了函数组件的功能性和灵活性。
     state 与 props

     在上述两个例子中,我们都提到了状态(state)和 props,并且在类组件中我们还使用了 props;那究竟什么是state和props呢?
     props

     React 组件使用 props 相互通讯。props 是父组件向子组件通报数据的方式。无论是函数组件还是类组件,都可以接收 props。props 是只读的,也就是说:子组件不能修改父组件通报过来的 props。props 可能会让您想起 HTML 属性,可以通报任何 JavaScript 值,包括对象、数组和函数
     将 props 通报给组件

     在下面这段代码中,Profile 组件没有向其子组件 Avatar 通报任何参数:
                                   登录后复制                        
  1. function Avatar() {
  2.     return (
  3.         <img
  4.             className="avatar"
  5.             src="https://i.imgur.com/1bX5QH6.jpg"
  6.             alt="Lin Lanying"
  7.             width={100}
  8.             height={100}
  9.         />
  10.     );
  11. }
  12. export default function Profile() {
  13.     return <Avatar />;
  14. }
复制代码
      
                       类组件写法如下:
                                   登录后复制                        
  1. class Avatar extends Component {
  2.     render() {
  3.         return (
  4.             <img
  5.                 className="avatar"
  6.                 src="https://i.imgur.com/1bX5QH6.jpg"
  7.                 alt="Lin Lanying"
  8.                 width={100}
  9.             />
  10.         );
  11.     }
  12. }
  13. class Profile extends Component {
  14.     render() {
  15.         return (<Avatar />);
  16.     }
  17. }
复制代码
      
                       如果要给 Avatar 组件添加参数,可以经过下面的流程:
                                        登录后复制                        
  1. export default function Profile() {
  2.     return (
  3.         <Avatar
  4.             person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
  5.             size={100}
  6.         />
  7.     );
  8. }
复制代码
      
                       类组件的写法就是:
                                   登录后复制                        
  1. class Profile extends Component {
  2.     render() {
  3.         return <Avatar person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} />;
  4.     }
  5. }
复制代码
      
                       2.读取子组件内部的 props
                                   登录后复制                        
  1. function Avatar({ person, size }) {
  2.     return (
  3.         <img
  4.             className="avatar"
  5.             src={getImageUrl(person)}
  6.             alt={person.name}
  7.             width={size}
  8.             height={size}
  9.         />
  10.     );
  11. }
  12. export default function Profile() {
  13.     return (
  14.         <div>
  15.             <Avatar
  16.                 size={100}
  17.                 person={{
  18.                     name: 'Katsuko Saruhashi',
  19.                     imageId: 'YfeOqp2',
  20.                 }}
  21.             />
  22.             <Avatar
  23.                 size={80}
  24.                 person={{
  25.                     name: 'Aklilu Lemma',
  26.                     imageId: 'OKS67lh',
  27.                 }}
  28.             />
  29.             <Avatar
  30.                 size={50}
  31.                 person={{
  32.                     name: 'Lin Lanying',
  33.                     imageId: '1bX5QH6',
  34.                 }}
  35.             />
  36.         </div>
  37.     );
  38. }
  39. function getImageUrl(person, size = 's') {
  40.     return 'https://i.imgur.com/' + person.imageId + size + '.jpg';
  41. }
复制代码
      
                       类组件的写法:
                                   登录后复制                        
  1. import React, { Component } from 'react';
  2. class Avatar extends Component {
  3.     render() {
  4.         const { person, size } = this.props;
  5.         return (
  6.             <img
  7.                 className="avatar"
  8.                 src={getImageUrl(person)}
  9.                 alt={person.name}
  10.                 width={size}
  11.             />
  12.         );
  13.     }
  14. }
  15. export default class Profile extends Component {
  16.     render() {
  17.         return (
  18.             <>
  19.                 <Avatar
  20.                     size={100}
  21.                     person={{
  22.                         name: 'Katsuko Saruhashi',
  23.                         imageId: 'YfeOqp2',
  24.                     }}
  25.                 />
  26.                 <Avatar
  27.                     size={80}
  28.                     person={{
  29.                         name: 'Aklilu Lemma',
  30.                         imageId: 'OKS67lh',
  31.                     }}
  32.                 />
  33.                 <Avatar
  34.                     size={50}
  35.                     person={{
  36.                         name: 'Lin Lanying',
  37.                         imageId: '1bX5QH6',
  38.                     }}
  39.                 />
  40.             </>
  41.         );
  42.     }
  43. }
  44. function getImageUrl(person, size = 's') {
  45.     return 'https://i.imgur.com/' + person.imageId + size + '.jpg';
  46. }
复制代码
      
                       state

     在 React 中,state 是组件内部管理和存储数据的一种机制。明白 React 中的 state 非常紧张,因为它决定了组件的状态和举动,直接影响到组件的渲染和交互。
     state 是一个 JavaScript 对象,用于存储组件的内部数据;每个组件可以有本身的 state,用来描述组件当前的状态。
     作用
     
     使用场景
     
     如何使用 State

     初始化 State

     
                                   登录后复制                        
  1. class MyComponent extends React.Component {
  2.     constructor(props) {
  3.         super(props);
  4.         this.state = {
  5.             count: 0,
  6.             name: 'John',
  7.         };
  8.     }
  9.     // ...
  10. }
复制代码
      
                       
                                   登录后复制                        
  1. function MyComponent() {
  2.     const [count, setCount] = useState(0);
  3.     const [name, setName] = useState('John');
  4.     // ...
  5. }
复制代码
      
                       访问 State

     
                                   登录后复制                        
  1. render() {
  2.     return <p>Hello, {this.state.name}!</p>;
  3. }
复制代码
      
                       
                                   登录后复制                        
  1. return <p>Hello, {name}!</p>;
复制代码
      
                       更新 State

     
                                   登录后复制                        
  1. this.setState({ count: this.state.count + 1 });
复制代码
      
                       
                                   登录后复制                        
  1. setCount(count + 1);
复制代码
      
                       异步更新

     
                                   登录后复制                        
  1. this.setState(prevState => ({
  2.     count: prevState.count + 1
  3. }));
复制代码
      
                       完整代码如下:
     
                                   登录后复制                        
  1. class MyComponent extends React.Component {
  2.     constructor(props) {
  3.         super(props);
  4.     }
  5.     state = {
  6.         count: 0,
  7.         name: 'John',
  8.     };
  9.     render() {
  10.         return (
  11.             <div>
  12.                 <p>{this.state.count}</p>
  13.                 <p>{this.state.name}</p>
  14.             </div>
  15.         );
  16.     }
  17. }
复制代码
      
                       
                                   登录后复制                        
  1. function MyComponent() {
  2.     const [count, setCount] = useState(0);
  3.     const [name, setName] = useState('John');
  4.     return (
  5.         <div>
  6.             <p>{count}</p>
  7.             <p>{name}</p>
  8.         </div>
  9.     );
  10. }
复制代码
      
                       生命周期

     通过上面的例子,我们知道 React 会把状态的变动更新到 UI,然后页面显示的内容更新,状态的变动过程必然会履历组件的生命周期。起主要知道所谓生命周期,就是组件从开始生成到最后消亡的过程, React 通常将组件生命周期分为三个阶段:装载、更新和卸载,我们怎么能确定组件进入到了哪个阶段呢?通过 React 组件袒露给我们的钩子函数就可以知晓。接下来我们将一起学习 React 组件的生命周期。
     16.3 版本之前
     

     16.3 版本
     

     16.4 及之后
     

     通过上面的图片,我们可以看到 getDerivedStateFromProps 在 React v16.4 中有肯定的改动,这个函数会在每次 render 之前被调用,也就意味着纵然你的 props 没有任何变化,由父组件的 state 的改动导致的 render,这个生命周期依然会被调用,使用的时候需要注意。
     根据上面的图片可以看出,在 React v16.4 中,getDerivedStateFromProps 方法有了一些改动。现在,这个生命周期方法在每次组件即将渲染之前都会被调用,不再只在接收新 props 时触发。这意味着,纵然组件的 props 没有实际变化,只要父组件的 state 发生改变导致重新渲染,这个生命周期方法也会被实行。因此,在使用时需要特别注意这一点。
     挂载阶段

     挂载阶段组件被创建,然后组件实例插入到 DOM 中,完成组件的第一次渲染,该过程只会发生一次,在此阶段会依次调用以下这些方法:
     
     constructor

     组件的构造函数是第一个被实行的部分。如果我们显式界说了构造函数,就必须在其中调用 super(props),这样才华确保在构造函数内部正确获取到 this。这涉及到了 ES6 类的继承机制,具体内容可以参考阮一峰的 《ECMAScript 6 入门》。
     在构造函数里一般会做两件事:
     
                                   登录后复制                        
  1. constructor(props) {
  2.   super(props);
  3.   // 不要在构造函数中调用 setState,可以直接给 state 设置初始值
  4.   this.state = { counter: 0 };
  5.   this.handleClick = this.handleClick.bind(this);
  6. }
复制代码
      
                       getDerivedStateFromProps

     这是一个静态方法,因此不能在其内部使用 this。它接收两个参数:
     
     该方法应返回一个对象,用于更新当前的状态对象;如果不需要更新,则返回 null。这个方法会在组件挂载时或者接收到新的 props、或调用了 setState 和 forceUpdate 时被调用。比方,当我们接收到新的属性并希望更新状态时,可以在此方法内进行处置惩罚。
                                   登录后复制                        
  1. // 当 props.counter 变化时,赋值给 state
  2. class App extends React.Component {
  3.     constructor(props) {
  4.         super(props);
  5.         this.state = {
  6.             counter: 0,
  7.         };
  8.     }
  9.     static getDerivedStateFromProps(props, state) {
  10.         // 如果 props.counter 变化了,那么就返回新的 state
  11.         if (props.counter !== state.counter) {
  12.             return {
  13.                 counter: props.counter,
  14.             };
  15.         }
  16.         return null;
  17.     }
  18.     handleClick = () => {
  19.         this.setState({
  20.             count: this.state.count + 1,
  21.         });
  22.     };
  23.     render() {
  24.         return (
  25.             <div>
  26.                 <p>Count: {count}</p>
  27.                 <button onClick={this.handleClick}>Increment</button>
  28.             </div>
  29.         );
  30.     }
  31. }
复制代码
      
                       现在我们可以显式传入 counter,但出现了一个小题目:如果我们希望通过点击变乱来增长 state.counter 的值,会发现它始终保持着 props 传入的初始值,没有发生任何变化。这是因为在 React 16.4 及更高版本中,setState 和 forceUpdate 也会触发 getDerivedStateFromProps 生命周期方法。因此,当组件内部的状态发生变化时,会再次调用该方法,并将状态值重置为 props 的值。为相识决这个题目,我们需要在 state 中添加一个额外的字段来记载之前的 props 值。
                                   登录后复制                        
  1. import React from 'react';
  2. export default class GetDerivedStateFromProps extends React.Component {
  3.     constructor(props) {
  4.         super(props);
  5.         this.state = {
  6.             // 增加一个 preCounter 来记录之前的 props 传来的值
  7.             preCounter: 0,
  8.             counter: 0,
  9.         };
  10.     }
  11.     static getDerivedStateFromProps(props, state) {
  12.         // 如果 props.counter 变化了,那么就返回新的 state
  13.         if (props.counter !== state.preCounter) {
  14.             return {
  15.                 counter: props.counter,
  16.                 preCounter: props.preCounter,
  17.             };
  18.         }
  19.         return null;
  20.     }
  21.     handleClick = () => {
  22.         this.setState({
  23.             count: this.state.count + 1,
  24.         });
  25.     };
  26.     render() {
  27.         return (
  28.             <div>
  29.                 <p>Count: {count}</p>
  30.                 <button onClick={this.handleClick}>Increment</button>
  31.             </div>
  32.         );
  33.     }
  34. }
复制代码
      
                       render

     React 中最焦点的方法是 render 方法。一个 React 组件必须包罗 render 方法,它根据组件的状态 state 和属性 props 来决定返回什么内容,从而渲染组件到页面上。
     在 render 方法中,通常会返回以下范例中的一个:
     
     componentDidMount

     在组件挂载后调用 componentDidMount 方法时,我们可以获取到 DOM 节点并进行操作,比方对 canvas、svg 进行绘制,或者发起服务器请求等操作。
     然而,需要注意的是,在 componentDidMount 中调用 setState 会触发一次额外的渲染过程,导致多一次 render 方法的实行。尽管这次渲染是在浏览器刷新屏幕进步行的,用户通常不会察觉到,但在开辟过程中,应尽量避免这种做法以避免潜在的性能题目。为了优化性能,我们应该尽早在 constructor 中初始化组件的 state 对象,而不是在 componentDidMount 中进行状态的初始化操作。
     在组件挂载之后,将计数数字变为10。
                                   登录后复制                        
  1. import React from 'react';
  2. export default class ComponentDidMount extends React.Component {
  3.     constructor(props) {
  4.         super(props);
  5.         this.state = {
  6.             counter: 0,
  7.         };
  8.     }
  9.     componentDidMount() {
  10.         this.setState({
  11.             counter: 10,
  12.         });
  13.     }
  14.     render() {
  15.         return <div className="counter">counter值: {this.state.counter}</div>;
  16.     }
  17. }
复制代码
      
                       更新阶段

     当组件的 props 改变了,或者组件内部调用了 setState 或 forceUpdate 方法,都会触发更新和重新渲染的过程。在这个阶段,React 组件会按照以下次序依次调用这些方法:
     
     这些方法协同工作,确保 React 组件可以或许相应外部变化,并实时更新用户界面。
     getDerivedStateFromProps

     这个方法在挂载阶段已经说过了,这里不再赘述,记住在更新阶段,无论接收到新的 props,还是调用了 setState 或者 forceUpdate,这个方法都会被触发
     shouldComponentUpdate

                                   登录后复制                        
  1. shouldComponentUpdate(nextProps, nextState)
复制代码
      
                       在讲这个生命周期函数之前,我们先来探究两个题目:
                                        登录后复制                        
  1. this.setState({number: this.state.number})
复制代码
      
                            我们先探究上面两个题目:
     第一个题目:当 setState 被调用时,React 会更新组件的状态并重新渲染组件。setState 会归并新的状态对象到当前状态,然后触发 render 方法。 这是 React 的默认举动,用于确保组件反映最新的状态和 props。
     当然也有特殊环境,如果在 setState 中更新的状态与当前状态雷同,React 可能会跳过重新渲染。 在这种环境下,setState 被调用了,但是状态对象 { number: this.state.number } 与之前的状态雷同。React 进行状态归并后,发现新的状态和之前的状态没有变化,默认环境下,React 会优化跳过 render 调用,避免不须要的渲染。这种优化有助于提升性能,避免不须要的计算和 DOM 操作。
     第二个题目:如果是父组件重新渲染时,不管传入的 props 有没有变化,都会引起子组件的重新渲染。那么有没有什么方法解决在这两个场景下不让组件重新渲染进而提升性能呢?
     React 通过以下机制来优化和控制组件的重新渲染:
     
                                   登录后复制                        
  1. import React, { Component } from 'react';
  2. class ShallowCompare extends Component {
  3.     constructor(props) {
  4.         super(props);
  5.         this.state = {
  6.             number: 1,
  7.         };
  8.     }
  9.     updateNumber = () => {
  10.         this.setState({ number: this.state.number }, () => {
  11.             console.log('updated state:', this.state);
  12.         });
  13.     };
  14.     componentDidMount() {
  15.         console.log('updated number');
  16.     }
  17.     shouldComponentUpdate(nextProps, nextState) {
  18.         // 仅当 state 中的 number 改变时才重新渲染组件
  19.         return nextState.number !== this.state.number;
  20.     }
  21.     render() {
  22.         console.log('render called');
  23.         return (
  24.             <div>
  25.                 <p>Number: {this.state.number}</p>
  26.                 <button onClick={this.updateNumber}>Update Number</button>
  27.             </div>
  28.         );
  29.     }
  30. }
  31. export default ShallowCompare;
复制代码
      
                       卸载阶段

     在 React 的卸载阶段(Unmounting Phase),只有一个生命周期函数:componentWillUnmount。这个函数在组件即将从 DOM 中移除之前调用。在这一阶段,你可以实行一些须要的清理操作,以确保组件被正确地释放,并防止内存泄漏和其他潜在题目。
     典范用法

     
                                   登录后复制                        
  1. componentWillUnmount() {
  2.     if (this.timerID) {
  3.         clearTimeout(this.timerID);
  4.     }
  5. }
复制代码
      
                       
                                   登录后复制                        
  1. componentWillUnmount() {
  2.     if (this.networkRequest) {
  3.         this.networkRequest.abort(); // 假设我们有一个可以中止的请求
  4.     }
  5. }
复制代码
      
                       
                                   登录后复制                        
  1. componentWillUnmount() {
  2.     window.removeEventListener('resize', this.handleResize);
  3. }
复制代码
      
                       
                                   登录后复制                        
  1. componentWillUnmount() {
  2.     if (this.websocket) {
  3.         this.websocket.close(); // 关闭 WebSocket 连接
  4.     }
  5. }
复制代码
      
                       生命周期所演示的代码都可以在 github 上找到。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4