You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS:如何在对象数组中添加对象?分页筛选场景实现

Got it, let's get this working properly for you! I've put together a complete React component that meets all your requirements: grouping items 3 per page, pagination controls, alphabetical filtering, and a working add item feature that correctly integrates with your filtered list.

Complete Working Implementation

Here's the full code with explanations of key improvements:

import React, { Component } from 'react';

class ItemList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // 维护原始数据源,filtered列表会基于这个动态生成
      originalItems: [
        { id: 1, name: "Apple" },
        { id: 2, name: "Banana" },
        { id: 3, name: "Cherry" },
        { id: 4, name: "Date" },
        { id: 5, name: "Elderberry" },
      ],
      filterText: "", // 字母筛选的输入值
      inputValue: "", // 添加新项的输入值
      currentPage: 0,
      itemsPerPage: 3,
    };
  }

  // 动态计算过滤后的数组,保证数据一致性
  getFilteredItems = () => {
    const { originalItems, filterText } = this.state;
    if (!filterText.trim()) return originalItems;
    // 不区分大小写的前缀匹配,支持首字母或完整名称筛选
    return originalItems.filter(item => 
      item.name.toLowerCase().startsWith(filterText.toLowerCase())
    );
  };

  goToPrevPage = () => {
    this.setState(prev => ({
      currentPage: Math.max(prev.currentPage - 1, 0)
    }));
  };

  goToNextPage = () => {
    const filteredItems = this.getFilteredItems();
    const maxPage = Math.ceil(filteredItems.length / this.state.itemsPerPage) - 1;
    this.setState(prev => ({
      currentPage: Math.min(prev.currentPage + 1, maxPage)
    }));
  };

  handleFilterChange = (e) => {
    this.setState({
      filterText: e.target.value,
      currentPage: 0, // 筛选后自动回到第一页
    });
  };

  handleInputChange = (e) => {
    this.setState({ inputValue: e.target.value });
  };

  addItem = () => {
    const { inputValue, originalItems } = this.state;
    // 空值不添加,避免无效项
    if (!inputValue.trim()) return;

    // 生成唯一ID,避免重复key问题(你原来的固定id:0会导致渲染错误)
    const newItem = {
      id: originalItems.length > 0 ? Math.max(...originalItems.map(i => i.id)) + 1 : 1,
      name: inputValue.trim()
    };

    // 更新原始数组,而不是直接修改filtered,这样筛选状态下新项也会被正确处理
    this.setState(prev => ({
      originalItems: [...prev.originalItems, newItem],
      inputValue: "", // 添加后清空输入框
      currentPage: 0, // 回到第一页查看新项
    }));
  };

  render() {
    const { currentPage, itemsPerPage, filterText, inputValue } = this.state;
    const filteredItems = this.getFilteredItems();
    // 截取当前页要显示的项
    const currentItems = filteredItems.slice(
      currentPage * itemsPerPage,
      (currentPage + 1) * itemsPerPage
    );
    const maxPage = Math.ceil(filteredItems.length / itemsPerPage) - 1;

    return (
      <div style={{ padding: "20px", maxWidth: "600px", margin: "0 auto" }}>
        {/* 字母筛选区域 */}
        <div style={{ marginBottom: "15px" }}>
          <label>按字母筛选:</label>
          <input
            type="text"
            value={filterText}
            onChange={this.handleFilterChange}
            placeholder="输入首字母或名称"
            style={{ marginLeft: "10px", padding: "5px" }}
          />
        </div>

        {/* 添加新项区域 */}
        <div style={{ marginBottom: "15px" }}>
          <input
            type="text"
            value={inputValue}
            onChange={this.handleInputChange}
            placeholder="输入新名称"
            style={{ padding: "5px" }}
          />
          <button onClick={this.addItem} style={{ marginLeft: "10px", padding: "5px 10px" }}>
            添加
          </button>
        </div>

        {/* 列表显示区域 */}
        <ul style={{ listStyle: "none", padding: 0 }}>
          {currentItems.length > 0 ? (
            currentItems.map(item => (
              <li key={item.id} style={{ padding: "8px", borderBottom: "1px solid #eee" }}>
                {item.name}
              </li>
            ))
          ) : (
            <li style={{ padding: "8px" }}>没有匹配的内容</li>
          )}
        </ul>

        {/* 分页控制区域 */}
        <div style={{ marginTop: "15px" }}>
          <button
            onClick={this.goToPrevPage}
            disabled={currentPage === 0}
            style={{ padding: "5px 10px", marginRight: "10px" }}
          >
            上一页
          </button>
          <button
            onClick={this.goToNextPage}
            disabled={currentPage >= maxPage}
            style={{ padding: "5px 10px" }}
          >
            下一页
          </button>
          <span style={{ marginLeft: "15px" }}>
            第 {currentPage + 1} 页 / 共 {maxPage + 1} 页
          </span>
        </div>
      </div>
    );
  }
}

export default ItemList;

Key Fixes & Improvements Over Your Original Code

  • Avoided Direct Filtered Array Modification: Instead of pushing directly to filtered, we maintain an originalItems source array. The filtered list is computed dynamically based on this source and the current filter text—this ensures data consistency (e.g., new items will automatically respect active filters).
  • Unique ID Generation: Your original code used a fixed id: 0 which would cause React rendering errors due to duplicate keys. Now we generate a unique ID based on the highest existing ID in the array.
  • Input Validation: We don't allow empty values to be added to the list.
  • Better Pagination Logic: Added disabled states for pagination buttons to prevent invalid page navigation, and show clear page number feedback.
  • User Experience Touches: Clears the input field after adding an item, and resets to the first page so users immediately see their new entry.

内容的提问来源于stack exchange,提问作者Jota

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:03:52