ReactJS 教程

ReactJS - 主页 ReactJS - 简介 ReactJS - 路线图 ReactJS - 安装 ReactJS - 功能 ReactJS - 优势和缺点 ReactJS - 架构 ReactJS - 创建 React 应用程序 ReactJS - JSX ReactJS - 组件 ReactJS - 嵌套组件 ReactJS - 使用组件 ReactJS - 集合组件 ReactJS - 样式 ReactJS - 属性 (props) ReactJS - 使用属性创建组件 ReactJS - props 验证 ReactJS - 构造函数 ReactJS - 组件生命周期 ReactJS - 事件管理 ReactJS - 创建事件感知组件 ReactJS - Expense Manager 事件 ReactJS - 状态管理 ReactJS - 状态管理 API ReactJS - 无状态组件 ReactJS - Hooks 进行状态管理 ReactJS - Hooks 的组件生命周期 ReactJS - 布局组件 ReactJS - 分页 ReactJS - Material UI ReactJS - Http 客户端编程 ReactJS - 表单编程 ReactJS - 受控组件 ReactJS - 非受控组件 ReactJS - Formik ReactJS - 条件渲染 ReactJS - 列表 ReactJS - Key 键 ReactJS - 路由 ReactJS - Redux ReactJS - 动画 ReactJS - Bootstrap ReactJS - Map ReactJS - 表格 ReactJS - 使用 Flux 管理状态 ReactJS - 测试 ReactJS - CLI 命令 ReactJS - 构建和部署 ReactJS - 示例

Hooks

ReactJS - Hooks 简介 ReactJS - 使用 useState ReactJS - 使用 useEffect ReactJS - 使用 useContext ReactJS - 使用 useRef ReactJS - 使用 useReducer ReactJS - 使用 useCallback ReactJS - 使用 useMemo ReactJS - 自定义 Hooks

ReactJS 高级

ReactJS - 可访问性 ReactJS - 代码拆分 ReactJS - 上下文 ReactJS - 错误边界 ReactJS - 转发 Refs ReactJS - 片段 ReactJS - 高阶组件 ReactJS - 与其他库集成 ReactJS - 优化性能 ReactJS - Profiler API ReactJS - Portals ReactJS - 不使用 ES6 ECMAScript ReactJS - 不使用 JSX 的 React ReactJS - Reconciliation ReactJS - Refs 和 DOM ReactJS - 渲染道具 ReactJS - 静态类型检查 ReactJS - 严格模式 ReactJS - Web 组件

其他概念

ReactJS - 日期选择器 ReactJS - Helmet ReactJS - 内联样式 ReactJS - PropTypes ReactJS - BrowserRouter ReactJS - DOM ReactJS - 轮播 ReactJS - 图标 ReactJS - 表单组件 ReactJS - 参考 API

ReactJS 有用资源

ReactJS - 快速指南 ReactJS - 备忘录 Axios - 备忘录 ReactJS - 有用资源 ReactJS - 讨论


ReactJS - getSnapshotBeforeUpdate() 方法

众所周知,React 中的每个组件都有自己的生命周期,这意味着它们在我们的项目中运行时会经历不同的阶段。React 提供了内置方法来控制这些过程。

现在让我们来看看 getSnapshotBeforeUpdate() 方法。假设我们正在使用 React 创建一个网页和一个定期接收消息的聊天组件。现在,我们不希望每次收到新消息时滚动位置都会发生变化。让用户忘记对话中的位置。这就是 getSnapshotBeforeUpdate 的作用所在。

简单来说,React 会在修改网页之前调用此函数。它允许我们的组件在任何潜在变化发生之前从页面捕获一些信息,例如用户滚动到的位置。

语法

getSnapshotBeforeUpdate(prevProps, prevState)

参数

  • prevProps − 这些是更改之前存在的属性。可以将它们与 this.props 进行比较以查看新内容。

  • prevState − 这是更改之前的先前状态。要确定更改,请将其与 this.state 进行比较。

返回值

我们应该返回任何类型的快照值或 null。我们返回的值将作为第三个参数发送到 componentDidUpdate。

示例

示例 1

让我们构建一个使用 getSnapshotBeforeUpdate 函数的小型 React 应用。在此示例中,我们将构建一个简单的聊天应用程序,其中有新消息,我们希望保存滚动位置。

import React, { Component } from 'react';

class App extends Component {
   constructor(props) {
      super(props);
      this.state = {
         messages: [
            { id: 1, text: 'Hello!' },
            { id: 2, text: 'How are you?' },
         ],
         newMessage: '',
      };
   
      this.chatWindowRef = React.createRef();
   }   
   handleInputChange = (event) => {
      this.setState({ newMessage: event.target.value });
   };   
   handleSendMessage = () => {
      const { messages, newMessage } = this.state;
      
      // 创建新的消息对象
      const newMessageObj = {
         id: messages.length + 1,
         text: newMessage,
      };
      
      // 使用新消息更新状态
      this.setState({
         messages: [...messages, newMessageObj],
         newMessage: '',
      });
   };   
   getSnapshotBeforeUpdate(prevProps, prevState) {
      // 检查是否有新消息被添加
      if (prevState.messages.length < this.state.messages.length) {
         const chatWindow = this.chatWindowRef.current;
         return chatWindow.scrollHeight - chatWindow.scrollTop;
      }
      return null;
   }   
   componentDidUpdate(prevProps, prevState, snapshot) {
      // 如果有快照,请调整滚动位置
      if (snapshot !== null) {
         const chatWindow = this.chatWindowRef.current;
         chatWindow.scrollTop = chatWindow.scrollHeight - snapshot;
      }
   }   
   render() {
      const { messages, newMessage } = this.state;      
      return (
         <div>
            <div
               ref={this.chatWindowRef}
               style={{ height: '200px', overflowY: 'scroll', border: '1px solid #ccc', padding: '10px' }}
               >
               {/* Display messages */}
               {messages.map((message) => (
                  <div key={message.id}>{message.text}</div>
               ))}
            </div>
               
               {/* Input for new message */}
               <div>
                  <input type="text" value={newMessage} onChange={this.handleInputChange} />
                  <button onClick={this.handleSendMessage}>Send Message</button>
            </div>
         </div>
      );
   }
}

export default App;

输出

send message

在此应用程序中 −

  • ChatApp 组件保留一个消息列表和一个用于添加新消息的表单。

  • 函数 getSnapshotBeforeUpdate 用于查明是否有新消息添加并记录当前滚动位置。

  • 如果添加了新消息,componentDidUpdate 将更新滚动位置。

  • 聊天窗口包含一个可滚动区域用于显示消息。

示例 2

让我们创建一个简单的 React 应用程序,用户可以在其中输入数字并执行基本的算术运算。以下是代码 −

import React, { Component } from 'react';
import './App.css';

class CalculatorApp extends Component {
   constructor(props) {
      super(props);
      this.state = {
         result: 0,
         num1: '',
         num2: '',
         operator: '+',
      };
   }   
   handleNumChange = (event, numType) => {
      const value = event.target.value;
   
      this.setState({
         [numType]: value,
      });
   };   
   handleOperatorChange = (event) => {
      this.setState({
         operator: event.target.value,
      });
   };   
   handleCalculate = () => {
      const { num1, num2, operator } = this.state;
      
      // 将输入值转换为数字
      const number1 = parseFloat(num1);
      const number2 = parseFloat(num2);
      
      // 根据所选运算符进行计算
      let result = 0;
      switch (operator) {
         case '+':
            result = number1 + number2;
         break;
         case '-':
            result = number1 - number2;
         break;
         case '*':
            result = number1 * number2;
         break;
         case '/':
            result = number1 / number2;
         break;
         default:
         break;
      }
      
      // 使用结果更新状态
      this.setState({
         result,
      });
   };
   
   render() {
      const { result, num1, num2, operator } = this.state;      
      return (
         <div className='App'>
            <div>
               <input type="number" value={num1} onChange={(e) => this.handleNumChange(e, 'num1')} />
               <select value={operator} onChange={this.handleOperatorChange}>
                  <option value="+">+</option>
                  <option value="-">-</option>
                  <option value="*">*</option>
                  <option value="/">/</option>
               </select>
               <input type="number" value={num2} onChange={(e) => this.handleNumChange(e, 'num2')} />
               <button onClick={this.handleCalculate}>Calculate</button>
            </div>
            <div>
               <strong>Result:</strong> {result}
            </div>
         </div>
      );
   }
}

export default CalculatorApp;

输出

计算结果

在此代码中,我们创建了一个简单的计算器应用,用户可以在其中输入两个数字,选择一个算术运算符,并在单击"计算"按钮后查看结果。

示例 3

让我们创建一个小型 React 应用,让用户输入任务并将其标记为已完成。添加新任务时,我们将使用 getSnapshotBeforeUpdate 函数滚动到任务列表的底部。以下是该应用的代码 −

import React, { Component } from 'react';

class TaskListApp extends Component {
   constructor(props) {
      super(props);
      this.state = {
         tasks: [],
         newTask: '',
      };
      
      this.taskListRef = React.createRef();
   }   
   handleInputChange = (event) => {
      this.setState({ newTask: event.target.value });
   };   
   handleAddTask = () => {
      const { tasks, newTask } = this.state;
      
      // 创建一个新的任务对象
      const newTaskObj = {
         id: tasks.length + 1,
         text: newTask,
         completed: false,
      };
      
      // 使用新任务更新状态
      this.setState({
         tasks: [...tasks, newTaskObj],
         newTask: '',
      });
   };
   
   getSnapshotBeforeUpdate(prevProps, prevState) {
      // 检查是否有新任务被添加
      if (prevState.tasks.length < this.state.tasks.length) {
         const taskList = this.taskListRef.current;
         return taskList.scrollHeight - taskList.scrollTop;
      }
      return null;
   }   
   componentDidUpdate(prevProps, prevState, snapshot) {
      if (snapshot !== null) {
         const taskList = this.taskListRef.current;
      taskList.scrollTop = taskList.scrollHeight - snapshot;
      }
   }   
   handleToggleComplete = (taskId) => {
      const updatedTasks = this.state.tasks.map((task) =>
         task.id === taskId ? { ...task, completed: !task.completed } : task
      );
      
      this.setState({
         tasks: updatedTasks,
      });
   };   
   render() {
      const { tasks, newTask } = this.state;      
      return (
         <div>
            <div
               ref={this.taskListRef}
               style={{ height: '200px', overflowY: 'scroll', border: '1px solid #ccc', padding: '10px' }}
            >
               {/* Display tasks */}
               {tasks.map((task) => (
                  <div key={task.id} style={{ textDecoration: task.completed ? 'line-through' : 'none' }}>
                  <input
                     type="checkbox"
                     checked={task.completed}
                     onChange={() => this.handleToggleComplete(task.id)}
                  />
                  {task.text}
                  </div>
               ))}
            </div>
            
            {/* Input for new task */}
            <div>
               <input type="text" value={newTask} onChange={this.handleInputChange} />
               <button onClick={this.handleAddTask}>Add Task</button>
            </div>
         </div>
      );
   }
}

export default TaskListApp;

输出

adding task

在此应用中,用户可以输入任务、将其标记为已完成,并在列表中查看任务。添加新任务时,函数 getSnapshotBeforeUpdate 用于滚动到任务列表的底部。

注意事项

  • 如果定义了 shouldComponentUpdate 并返回 false,则 React 将不会调用 getSnapshotBeforeUpdate。

  • 目前函数组件没有与 getSnapshotBeforeUpdate 直接等效的功能。如果我们需要此功能,则必须使用类组件。

总结

因此,我们已经了解了 getSnapshotBeforeUpdate() 函数的工作机制。并且我们还创建了一个小应用来展示该函数的用法。该组件可以包含到我们的 React 应用程序中,以展示 getSnapshotBeforeUpdate 如何在添加新内容时有助于维持滚动位置。

reactjs_reference_api.html