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

React Hooks实现健身房停车位预约应用的状态管理问题咨询

你的状态管理思路完全正确!

你的直觉没错——把状态放在ParkingLot组件中是最优选择,这完美契合React的「状态提升」原则:当多个子组件(比如ParkingSpace和FormContainer)需要共享或修改同一组数据时,将状态提升到它们最近的共同父组件里统一管理是最合理的方案。

下面我会一步步带你实现这个逻辑,同时修正代码里的小问题:

1. 把静态车位数组转为useState状态

首先,我们需要将你定义的静态spaces数组用useState包裹,这样才能动态修改车位的预约状态、表单显示状态等信息:

import { useState } from 'react';

// 注意组件名要大写(React规范)
const ParkingLot = (props) => {
  // 初始化车位状态
  const [spaces, setSpaces] = useState([
    {id: 1, name: "Chase", classTaken: "Level 2", reserved: true, form: false},
    {id: 2, name: "", classTaken: "", reserved: false, form: false},
    {id: 3, name: "", classTaken: "", reserved: false, form: false},
    {id: 4, name: "", classTaken: "", reserved: false, form: false},
    {id: 5, name: "", classTaken: "", reserved: false, form: false},
    {id: 6, name: "", classTaken: "", reserved: false, form: false}
  ]);

  // 处理「预约」按钮点击:切换对应车位的表单显示状态
  const handleReserveClick = (spaceId) => {
    setSpaces(prevSpaces => 
      prevSpaces.map(space => 
        space.id === spaceId ? {...space, form: true} : space
      )
    );
  };

  // 处理「取消预约」按钮点击:重置对应车位状态
  const handleCheckOutClick = (spaceId) => {
    setSpaces(prevSpaces => 
      prevSpaces.map(space => 
        space.id === spaceId ? {...space, name: "", classTaken: "", reserved: false, form: false} : space
      )
    );
  };

  // 处理表单提交:更新车位的预约信息
  const handleFormSubmit = (spaceId, name, classTaken) => {
    setSpaces(prevSpaces => 
      prevSpaces.map(space => 
        space.id === spaceId ? {...space, name, classTaken, reserved: true, form: false} : space
      )
    );
  };

  return (
    <div className="parking-lot">
      {spaces.map(space => {
        if (!space.form) {
          return (
            <div key={space.id} className="parking-space-wrapper">
              <ParkingSpace 
                id={space.id} 
                name={space.name} 
                classTaken={space.classTaken} 
                reserved={space.reserved} 
              />
              {space.reserved ? 
                <button onClick={() => handleCheckOutClick(space.id)}>Check Out</button> : 
                <button onClick={() => handleReserveClick(space.id)}>Reserve</button>
              }
            </div>
          );
        } else {
          // 渲染表单容器,并传递提交回调
          return <FormContainer key={space.id} id={space.id} onSubmit={handleFormSubmit} />;
        }
      })}
    </div>
  );
};

2. 完善ParkingSpace组件(仅做展示,无需状态)

这个组件只负责接收props并渲染车位信息,无需自己管理状态:

// 组件名大写
const ParkingSpace = (props) => {
  return (
    <div className="parking-space">
      <h4>Parking Space {props.id}</h4>
      {!props.reserved ? (
        <p>Currently Available</p>
      ) : (
        <div>
          <p>Checked Out By: {props.name}</p>
          <p>Taking Class: {props.classTaken}</p>
        </div>
      )}
    </div>
  );
};

3. 实现FormContainer组件(收集用户输入并回调)

这个组件需要收集用户的姓名和课程信息,提交时通过父组件传递的回调函数把数据传回ParkingLot:

const FormContainer = ({ id, onSubmit }) => {
  const [name, setName] = useState('');
  const [classTaken, setClassTaken] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    // 调用父组件的回调,传递车位ID和用户输入
    onSubmit(id, name, classTaken);
    // 重置表单输入
    setName('');
    setClassTaken('');
  };

  return (
    <form onSubmit={handleSubmit} className="reserve-form">
      <h4>Reserve Parking Space {id}</h4>
      <div>
        <label>Your Name:</label>
        <input 
          type="text" 
          value={name} 
          onChange={(e) => setName(e.target.value)} 
          required 
        />
      </div>
      <div>
        <label>Taking Class:</label>
        <input 
          type="text" 
          value={classTaken} 
          onChange={(e) => setClassTaken(e.target.value)} 
          required 
        />
      </div>
      <button type="submit">Confirm Reservation</button>
    </form>
  );
};

为什么这个状态设计符合《Thinking in React》的原则?

你提到的「状态不应是可从其他地方推导的信息」非常关键:

  • reserved:无法从其他字段推导(比如用户点击Reserve但未提交表单时,reserved还是false,但form是true)
  • name/classTaken:只有reserved为true时才有意义,且是用户输入的原始数据,无法推导
  • form:控制表单是否显示的状态,也无法从reserved或其他字段推导

所有状态都是必要的、不可替代的,完全符合React的状态设计原则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:28:49