快速掌握 React 基础入门: 一个完整的指南(三)

简介: 快速掌握 React 基础入门: 一个完整的指南

快速掌握 React 基础入门: 一个完整的指南(二)https://developer.aliyun.com/article/1426133


C. Updating 阶段

Updating 阶段是指一个已经挂载的组件在更新时的过程,更新可以由组件自身的 setState 方法、forceUpdate 方法,或父组件的重新渲染触发。

在 Updating 阶段,React 会自动调用以下生命周期函数(按照调用顺序):

  1. static getDerivedStateFromProps(props, state):静态函数,该函数会在虚拟 DOM 处理之前被调用,用于更新组件的状态。与 Mounting 阶段的调用方式相同。
  2. shouldComponentUpdate(nextProps, nextState):更新函数,用于决定组件是否需要更新。返回一个布尔值,如果返回 true,则执行更新操作,否则不进行更新。默认返回 true,即总是更新。
  3. render():渲染函数,返回组件的虚拟 DOM,用于显示在页面上。
  4. getSnapshotBeforeUpdate(prevProps, prevState):静态函数,用于获取组件更新前的 DOM 状态。可以在此函数中保存一些 DOM 状态,并在 componentDidUpdate 中恢复这些状态。
  5. componentDidUpdate(prevProps, prevState, snapshot):更新函数,用于在组件更新后进行一些额外的操作,例如重新计算 DOM 元素的位置、滚动条的位置等。

示例代码:

import React, { Component } from 'react';
class Example extends Component {
  constructor(props) {
    super(props);
    this.state = { value: 'Hello World' };
  }
  static getDerivedStateFromProps(props, state) {
    console.log('getDerivedStateFromProps', props, state);
    return null;
  }
  shouldComponentUpdate(nextProps, nextState) {
    console.log('shouldComponentUpdate', nextProps, nextState);
    return true;
  }
  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('getSnapshotBeforeUpdate', prevProps, prevState);
    return 'snapshot';
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('componentDidUpdate', prevProps, prevState, snapshot);
  }
  handleClick = () => {
    this.setState({ value: 'Hello React' });
  };
  render() {
    console.log('render');
    return (
      <div>
        <p>{this.state.value}</p>
        <button onClick={this.handleClick}>Click me</button>
      </div>
    );
  }
}
export default Example;

在这个例子中,我们为 Example 组件添加了一个按钮,当用户点击按钮时,会调用 handleClick 方法,将组件的 value 状态更新为 'Hello React'。此时,React 会自动调用 Updating 阶段的生命周期函数。

当用户点击按钮时,React 首先会调用 getDerivedStateFromProps 函数,返回 null。然后,React 会调用 shouldComponentUpdate 函数,返回 true。接着,React 调用 render 函数,更新组件的虚拟 DOM,并显示在页面上。在 render 函数执行完毕后,React 调用 getSnapshotBeforeUpdate 函数,返回字符串 'snapshot'。最后,React 调用 componentDidUpdate 函数,更新完成后,进行一些清理工作和其他操作,例如重新计算 DOM 元素的位置等。

D. Unmounting 阶段

Unmounting 阶段是指组件从页面中被卸载的过程,不再被渲染到页面上。卸载可能是由父组件的重新渲染、组件自身的 setState 方法、forceUpdate 方法,或使用 React 的 ReactDOM.unmountComponentAtNode 方法触发。

在 Unmounting 阶段,React 会自动调用以下生命周期函数(按照调用顺序):

  1. componentWillUnmount():卸载函数,用于在组件被卸载前进行清理操作,例如取消订阅、清除定时器等。

示例代码:

import React, { Component } from 'react';
class Example extends Component {
  constructor(props) {
    super(props);
    this.state = { value: 'Hello World' };
  }
  componentWillUnmount() {
    console.log('componentWillUnmount');
  }
  render() {
    console.log('render');
    return (
      <div>
        <p>{this.state.value}</p>
      </div>
    );
  }
}
export default Example;

在这个例子中,我们只实现了 componentWillUnmount 函数,并在组件卸载前输出了一条信息。当组件被卸载时,React 会自动调用该函数,进行清理操作。

需要注意的是,在卸载阶段,组件不会再被更新渲染到 DOM 中,因此在卸载阶段的生命周期函数中不能通过 setState 方法更新组件的状态,这样会导致 React 报错。

VIII. React 中的列表和 keys

在 React 中渲染列表时,可以使用 Array.map 方法进行遍历渲染。有时候,我们需要在渲染列表的时候给每个列表项分配一个唯一的标识,这个标识称为“key”。

React中使用key来标记列表项的唯一性,它可以帮助 React 快速判断出哪些列表项需要更新,从而提高操作性能。

在 React 中使用 key 的方式很简单,例如:

const listItems = items.map(item => (
  <li key={item.id}>
    {item.text}
  </li>
));
return (
  <ul>
    {listItems}
  </ul>
);

在上述代码中,我们使用了数组的 map 方法将 items 数组转成了一个列表,并给每个列表项分配了一个唯一的 key,React 会根据列表项的 key 来判断哪些列表项需要更新,哪些可以复用。这种方式避免了不必要的 DOM 操作,提高了操作性能。

需要注意的是,key 必须是唯一、稳定且可预测的,不能使用数组的索引作为 key,因为当数组顺序发生变化时,会导致 key 不再唯一,从而使 React 在渲染时出现问题。

另外,key 只是在兄弟节点之间必须是唯一的,它们不需要在全局唯一。如果列表项的 id 是全局唯一的,那么可以使用 id 作为 key。如果没有全局唯一的标识,可以使用组合的方式,例如使用 [item.id, index] 作为 key。

总结一下:

  • 在 React 中使用 key 来标记列表项的唯一性,可以提高操作性能。
  • key 必须是唯一、稳定且可预测的,不能使用数组的索引作为 key。
  • key 只需要在兄弟节点之间是唯一的,不需要在全局唯一。

IX. 条件渲染

在 React 中,可以使用条件渲染来根据组件的状态来显示或隐藏组件。条件渲染是指根据条件来决定是否渲染组件或组件的一部分。

React 有两种方式来实现条件渲染:

1. 使用条件运算符

在组件的 render 函数中,可以使用条件运算符 ? : 来根据条件渲染组件或组件的一部分,例如:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isLoggedIn: false };
  }
  render() {
    const isLoggedIn = this.state.isLoggedIn;
    return (
      <div>
        {isLoggedIn ? (
          <UserGreeting />
        ) : (
          <GuestGreeting />
        )}
      </div>
    );
  }
}
function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}

在上述代码中,根据 isLoggedIn 状态的值来渲染 UserGreetingGuestGreeting

2. 使用 && 运算符

在组件的 render 函数中,可以使用 && 运算符来根据条件渲染组件或组件的一部分,例如:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isLoggedIn: false };
  }
  render() {
    const isLoggedIn = this.state.isLoggedIn;
    return (
      <div>
        {isLoggedIn && <UserGreeting />}
        {!isLoggedIn && <GuestGreeting />}
      </div>
    );
  }
}

在上述代码中,根据 isLoggedIn 状态的值来渲染 UserGreetingGuestGreeting,这里使用了 &&! 运算符。

总结一下:

  • 条件渲染是指根据条件来决定是否渲染组件或组件的一部分。
  • React 可以使用条件运算符 ? :&& 运算符来实现条件渲染。
  • 条件渲染可以根据组件的状态来显示或隐藏组件,可以提高组件的动态性和灵活性。

X. React Hooks

A. useEffect

useEffect 是 React 16.8 之后新增的 Hook,它可以让函数组件具有类似于类组件的生命周期钩子函数。useEffect 接收一个回调函数和一个依赖数组作为参数,每当组件渲染时,React 会根据依赖数组中的值来决定是否执行回调函数。

useEffect 的使用方式如下:

import React, { useEffect } from 'react';
function Example() {
  useEffect(() => {
    // 在组件挂载和更新时会被调用
    console.log('componentDidMount and componentDidUpdate');
    return () => {
      // 在组件卸载和更新时会被调用
      console.log('componentWillUnmount and componentDidUpdate');
    };
  }, [props.value]); // 仅在 props.value 发生变化时执行回调函数
  return <div>{props.value}</div>;
}

在这个例子中,我们定义了一个函数组件 Example,并使用了 useEffect Hook。useEffect 接收一个回调函数和一个依赖数组作为参数,函数组件每次渲染时都会执行回调函数。当依赖数组中的值发生变化时,React 会重新执行回调函数。如果依赖数组为空,则函数组件只会在挂载和卸载时执行回调函数。

回调函数可以返回一个清理函数,用于在组件卸载前执行一些清理操作,例如取消订阅、关闭定时器等等。

需要注意的是,由于 useEffect 是在组件函数内部定义的,因此回调函数可以调用父组件中的 state 和 props,而不需要使用类组件中的生命周期函数来访问它们。

总结一下:

  • useEffect 是 React 16.8 之后新增的 Hook。
  • useEffect 接收一个回调函数和一个依赖数组作为参数,函数组件每次渲染时都会执行回调函数。
  • 当依赖数组中的值发生变化时,React 会重新执行回调函数。
  • 回调函数可以返回一个清理函数,用于在组件卸载前执行一些清理操作。
  • 由于 useEffect 是在组件函数内部定义的,因此回调函数可以调用父组件中的 state 和 props。

B. useState

useState 是 React 16.8.0 之后推出的一个 Hook 函数,它可以让函数组件具有状态(state)。

useState 的使用方式如下:

import { useState } from 'react';
function Example() {
  // 在函数组件中使用 useState Hook 来定义状态
  const [count, setCount] = useState(0);
  function handleClick() {
    // 使用 setCount 函数来更新状态
    setCount(count + 1);
  }
  return (
    <div>
      <p>You clicked {count} times.</p>
      <button onClick={handleClick}>Click Me</button>
    </div>
  );
}

在这个例子中,我们定义了一个函数组件 Example,并使用了 useState Hook 来定义状态。useState 接收一个状态的初始值作为参数,并返回一个数组,第一个元素是当前状态的值,第二个元素是用于更新状态的函数。每当 setCount 函数被调用时,React 会自动重新渲染函数组件,并把新的状态值传递给组件。在更新状态时,不需要手动去合并旧状态和新状态,React 会自动处理。

需要注意的是,由于 useState 是在组件函数内部定义的,因此可以在同一个组件函数中多次使用 useState 来定义多个状态。

总结一下:

  • useState 是 React 16.8 之后推出的 Hook 函数,可以让函数组件具有状态(state)。
  • useState 接收一个状态的初始值作为参数,并返回一个数组,第一个元素是当前状态的值,第二个元素是用于更新状态的函数。
  • 在更新状态时,不需要手动去合并旧状态和新状态,React 会自动处理。
  • useState 是在组件函数内部定义的,因此可以在同一个组件函数中多次使用 useState 来定义多个状态。

C. useContext

useContext 是 React 16.8.0 之后推出的 Hook 函数,它可以让函数组件消费 Context

在 React 中,Context 可以让我们在组件树中共享数据,无需一级一级手动传递数据。当应用程序规模较大时,Context 可以非常有用,帮助我们简化数据的传递和管理。

使用 useContext 可以让我们更轻松地从 Context 中读取数据。通常,我们需要首先创建一个 Context 对象,然后将其传递给使用它的组件,使用 useContext 函数从 Context 中读取数据。

接下来给出一个使用 useContext 函数的例子:

import React, { useContext } from 'react';
const UserContext = React.createContext({ name: 'Guest' });
function Example() {
  const user = useContext(UserContext);
  return (
    <div>
      <p>Hello, {user.name}!</p>
    </div>
  );
}

在上述例子中,我们创建了一个名为 UserContext 的 Context 对象,并提供一个默认值 { name: 'Guest' }。然后,在 Example 组件中使用 useContext 函数从 UserContext 中读取数据,因此在组件中可以直接访问 user 对象,不需要通过 props 层层传递数据。

需要注意的是,在使用 useContext 时,需要将 UserContext 对象作为参数传递给 useContext 函数,例如:

const user = useContext(UserContext);

总结一下:

  • useContext 是 React 16.8 之后推出的 Hook 函数,可以让函数组件消费 Context
  • Context 可以让我们在组件树中共享数据,无需一级一级手动传递数据。
  • 使用 useContext 函数可以更轻松地从 Context 中读取数据。
  • 在使用 useContext 时,需要将 Context 对象作为参数传递给 useContext 函数。

D. useReducer

useReducer 是 React 16.8.0 之后推出的 Hook 函数,可以方便地管理组件的状态。useReduceruseState 类似,都可以让函数组件管理状态,但 useReducer 更适用于复杂的状态逻辑。

useReducer 接收一个“reducer”函数和一个初始状态作为参数,返回一个数组,第一个元素是当前状态值,第二个元素是用于更新状态的 dispatch 函数。

下面是一个使用 useReducer 的例子:

import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}
function Example() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}

在这个例子中,我们定义了一个初始状态 { count: 0 } 和一个“reducer”函数 reducer,然后在 Example 组件中使用了 useReducer 来定义状态。useReducer 的第一个参数是 reducer 函数,第二个参数是初始状态。

在组件中可以通过 dispatch 函数来触发状态的更新,通过传入一个 action 对象来描述状态的变化。在 reducer 函数中根据 action.type 的值来更新状态,并返回一个新的状态对象。

需要注意的是,在使用 useReducer 时,尽量避免直接修改原有状态对象,应该返回一个新的状态对象。

总结一下:

  • useReducer 是 React 16.8 之后推出的 Hook 函数,可以方便地管理组件的状态。
  • useReducer 接收一个“reducer”函数和一个初始状态作为参数,返回一个数组。第一个元素是当前状态值,第二个元素是用于更新状态的 dispatch 函数。
  • useReducer 中,通过 dispatch 函数来触发状态的更新,在 reducer 函数中根据 action.type 的值来更新状态,并返回一个新的状态对象。
相关文章
|
1月前
|
前端开发 JavaScript 开发者
React:JSX语法入门
React:JSX语法入门
34 0
|
1月前
|
前端开发 JavaScript
React Hooks 入门基础(详细使用)
React Hooks 入门基础(详细使用)
32 0
|
11天前
|
前端开发
前端react入门day02-React中的事件绑定与组件
前端react入门day02-React中的事件绑定与组件
|
1月前
|
前端开发 JavaScript
快速掌握 React 基础入门: 一个完整的指南(二)
快速掌握 React 基础入门: 一个完整的指南
|
1月前
|
前端开发 JavaScript Linux
快速掌握 React 基础入门: 一个完整的指南(一)
快速掌握 React 基础入门: 一个完整的指南
|
1月前
|
前端开发 JavaScript 开发者
React中JSX语法入门
React中JSX语法入门
|
7月前
|
前端开发 JavaScript
React基础入门
React基础入门
41 0
|
9月前
|
存储 前端开发 JavaScript
【react从入门到精通】React兄弟组件通信方式详解(有示例)
在上一篇文章《[React父子组件通信方式详解]》中我们学习到了React父子组件通信的4中方式。本文中我们将详细了解react兄弟组件通信方式。
192 0
|
10月前
|
前端开发
前端学习笔记202305学习笔记第二十九天-React keep alive原理之2
前端学习笔记202305学习笔记第二十九天-React keep alive原理之2
44 0
|
10月前
|
前端开发
前端学习笔记202306学习笔记第四十八天-react-admin marmelab之8
前端学习笔记202306学习笔记第四十八天-react-admin marmelab之7
31 0