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

React映射时如何将组件渲染到两个不同div中?

React 优化任务列表渲染:避免重复编写<Task/>组件

我在React中将对象数组作为state(例如名为todos),用两个div分别存放未完成和已完成任务,映射时使用<Task/>组件。当前代码里重复写了两次<Task/>的映射逻辑,想让代码更简洁,是否可行?

我的初始state:

const [todos, setTodos] = useState([
    {id: 1, text: 'Lorem', isComplete: true},
    {id: 2, text: 'Ipsum', isComplete: true},
    {id: 3, text: 'Test', isComplete: false}
]);

当前的JSX结构(简化版):

return (     
    <div>
         <h1>Todos</h1>
         <p>今日待办:</p>
         <div id="incomplete"></div> 
         <p>已完成任务:</p>
         <div id="complete"></div>     
    </div> )

我现在的代码存在重复逻辑,不够简洁:

<div className='tasks'>
  <h2>Tasks</h2>
  <div className="tasks-incomplete">
    <h3>待完成任务</h3>
    {incompleteTasks.length > 0 && incompleteTasks.map(task => (
      <Task 
        key={task.id}
        id={task.id} 
        text={task.text} 
        isComplete={task.isComplete} 
        dateStart={task.dateStart}
        dateComplete={task.dateComplete}
        handleDeleteTask={() => handleDeleteTask(task.id)}
        handleClickEdit={()=>handleClickEdit(task.id, task.text)}
        handleComplete={()=>handleComplete(task.id)}
      />
      ))}
    {incompleteTasks.length === 0 && <p>暂无任务</p>}
  </div>
  
  {completeTasks.length > 0 && (
    <div id="completed" className="tasks-complete">
      <h3>已完成任务</h3>
      {completeTasks.map( task => (
        <Task 
          key={task.id}
          id={task.id} 
          text={task.text} 
          isComplete={task.isComplete} 
          dateStart={task.dateStart}
          dateComplete={task.dateComplete}
          handleDeleteTask={()=>handleDeleteTask(task.id)}
          handleClickEdit={()=>handleClickEdit(task.id, task.text)}
          handleComplete={()=>handleComplete(task.id)}
        /> 
      ))}
    </div>
  )}
  
</div>

优化方案:提取重复逻辑,减少代码冗余

1. 缓存拆分后的任务数组

先用useMemo缓存拆分后的任务数组,避免每次渲染重复计算:

import { useMemo } from 'react';

// ...

const incompleteTasks = useMemo(() => todos.filter(task => !task.isComplete), [todos]);
const completeTasks = useMemo(() => todos.filter(task => task.isComplete), [todos]);

2. 提取任务列表渲染函数

把重复的<Task/>映射逻辑抽成独立函数,接收任务数组作为参数:

const renderTaskList = (tasks) => {
  return tasks.map(task => (
    <Task 
      key={task.id}
      {...task} // 解构task对象,自动传入所有属性
      handleDeleteTask={() => handleDeleteTask(task.id)}
      handleClickEdit={() => handleClickEdit(task.id, task.text)}
      handleComplete={() => handleComplete(task.id)}
    />
  ));
};

3. 重构JSX代码

在JSX中直接调用上述函数,替换重复的映射逻辑:

return (
  <div className='tasks'>
    <h2>Tasks</h2>
    <div className="tasks-incomplete">
      <h3>待完成任务</h3>
      {incompleteTasks.length > 0 
        ? renderTaskList(incompleteTasks) 
        : <p>暂无任务</p>}
    </div>
    
    {completeTasks.length > 0 && (
      <div id="completed" className="tasks-complete">
        <h3>已完成任务</h3>
        {renderTaskList(completeTasks)}
      </div>
    )}
  </div>
);

4. 可选:封装任务列表组件(进一步复用)

如果这种任务分组的结构需要多次复用,可以封装成独立组件:

const TaskSection = ({ title, tasks, emptyText, handleDeleteTask, handleClickEdit, handleComplete }) => {
  if (tasks.length === 0) {
    return emptyText ? <div>{emptyText}</div> : null;
  }
  
  return (
    <div className={`tasks-${title === '待完成任务' ? 'incomplete' : 'complete'}`}>
      <h3>{title}</h3>
      {tasks.map(task => (
        <Task 
          key={task.id}
          {...task}
          handleDeleteTask={() => handleDeleteTask(task.id)}
          handleClickEdit={() => handleClickEdit(task.id, task.text)}
          handleComplete={() => handleComplete(task.id)}
        />
      ))}
    </div>
  );
};

主组件中使用:

return (
  <div className='tasks'>
    <h2>Tasks</h2>
    <TaskSection 
      title="待完成任务" 
      tasks={incompleteTasks} 
      emptyText={<p>暂无任务</p>}
      handleDeleteTask={handleDeleteTask}
      handleClickEdit={handleClickEdit}
      handleComplete={handleComplete}
    />
    <TaskSection 
      title="已完成任务" 
      tasks={completeTasks}
      handleDeleteTask={handleDeleteTask}
      handleClickEdit={handleClickEdit}
      handleComplete={handleComplete}
    />
  </div>
);

内容的提问来源于stack exchange,提问作者Łukasz Ro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 13:15:33