MST

星途 面试题库

面试题:React中getSnapshotBeforeUpdate在复杂列表动画中的应用

有一个可动态添加和删除列表项的React列表组件,当列表项删除时,希望剩余列表项能够平滑过渡填补空缺位置,类似CSS过渡动画效果。使用getSnapshotBeforeUpdate方法结合CSS的transition属性来实现该功能,描述实现思路并给出核心代码片段。
23.4万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. getSnapshotBeforeUpdate 方法中,记录删除项的索引位置和高度等相关信息。
  2. 在组件更新后,根据记录的信息,为剩余列表项添加相应的CSS过渡动画,使它们平滑地填补空缺位置。
  3. 使用CSS的 transition 属性定义过渡效果。

核心代码片段

import React, { Component } from 'react';
import './styles.css'; // 引入CSS文件定义过渡效果

class DynamicList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      items: ['Item 1', 'Item 2', 'Item 3']
    };
    this.handleDelete = this.handleDelete.bind(this);
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevState.items.length > this.state.items.length) {
      // 找到删除项的索引
      const deletedIndex = prevState.items.findIndex(item => 
        this.state.items.indexOf(item) === -1
      );
      // 获取删除项的高度(假设列表项有固定高度)
      const deletedItemHeight = document
      .querySelector(`.list-item:nth-child(${deletedIndex + 1})`)
      .offsetHeight;
      return { deletedIndex, deletedItemHeight };
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    if (snapshot) {
      const { deletedIndex, deletedItemHeight } = snapshot;
      // 为剩余列表项添加过渡效果
      const listItems = document.querySelectorAll('.list-item');
      for (let i = deletedIndex; i < listItems.length; i++) {
        listItems[i].style.transform = `translateY(-${deletedItemHeight}px)`;
        listItems[i].style.transition = 'transform 0.3s ease';
      }
      setTimeout(() => {
        // 移除过渡效果
        for (let i = deletedIndex; i < listItems.length; i++) {
          listItems[i].style.transform = 'translateY(0)';
          listItems[i].style.transition = 'none';
        }
      }, 300);
    }
  }

  handleDelete(index) {
    const { items } = this.state;
    items.splice(index, 1);
    this.setState({ items });
  }

  render() {
    const { items } = this.state;
    return (
      <div className="list">
        {items.map((item, index) => (
          <div key={index} className="list-item">
            {item}
            <button onClick={() => this.handleDelete(index)}>Delete</button>
          </div>
        ))}
      </div>
    );
  }
}

export default DynamicList;

styles.css

.list-item {
  padding: 10px;
  border-bottom: 1px solid #ccc;
}