首页 > 解决方案 > 在我的应用程序中实现状态的正确方法是什么

问题描述

我正在为我的健身房构建一个小应用程序,让会员可以预订我们的六个串联停车位(3x2 网格)中的一个。我试图构建这个应用程序只使用钩子作为一种学习方式,但无法弄清楚如何实现状态(下面的代码片段)。

基本上,我有一个 ParkingLot 组件,它映射到由六个停车位对象组成的数组并呈现一个 ParkingSpace 组件。当您单击空间的“保留”时,会加载一个 FormContainer 组件,该组件要求输入名称和所采用的类。我在“Thinking in React”中读到状态不应该是任何可以从其他地方派生的信息,这让我认为只有这个用户输入应该是我的状态,但它去哪里以及如何访问它在组件之间?我的直觉告诉我它应该存在于 ParkingLot 组件中。这个对吗?如果是这样,应该如何使用钩子来构建它?

const parkingLot = (props) => {
  const spaces = [{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}];

  return spaces.map(space => {
    if (space.form === false) {
      return (
        <div>
          <ParkingSpace key={space.id} id={space.id} name={space.name} classTaken={space.classTaken} reserved={space.reserved} />
          {
            (space.reserved)
            ? <button>Check Out</button>
            : <button>Reserve</button>
          }
        </div>
      )
    } else {
      <FormContainer id={space.id}/>
    }
  });
}

停车位组件

const space = (props) => {
  return (
    <div>
      <h4>Parking Space {props.id}</h4>
      {
        (props.reserved === false)
        ? <div>
            <p>Currently Available</p>
          </div>
        : <div>
            <p>Checked Out By: {props.name}</p>
            <p>Taking Class: {props.classTaken}</p>
          </div>
      }
    </div>
  )
};

预先感谢您的帮助。这是我关于 SO 的第一篇文章,所以请让我知道我是否可以更好地澄清或格式化任何内容。

标签: reactjs

解决方案


spaces数据用于确定 ParkingLot 组件的呈现方式——是否应显示表单以及描述每个空间的数据。因此,您不应该(也不能)将该数据存储在 Space 组件上。

您应该将整个spaces数据转换为 ParkingLot 组件上的单个状态(六个单独的状态也可以工作,但我认为这不是最好的方法)。然后,您可以像现在一样使用这些数据来渲染每个 Space 组件。要使复杂对象进入状态而不破坏它,您可以使用react-hooks-object-state允许使用挂钩进行部分对象更新。

import useObjectState from 'react-hooks-object-state';

const ParkingLot = (props) => {
  const [spaces, setSpaces] = useObjectState({
    space1: {id: 1, name: "Chase", classTaken: "Level 2", reserved: true, form: false},
    space2: {id: 2, name: "", classTaken: "", reserved: false, form: false},
    space3: {id: 3, name: "", classTaken: "", reserved: false, form: false},
    space4: {id: 4, name: "", classTaken: "", reserved: false, form: false},
    space5: {id: 5, name: "", classTaken: "", reserved: false, form: false},
    space6: {id: 6, name: "", classTaken: "", reserved: false, form: false}
  });
  ...
}

那么问题将是如何更新数据。在不知道您的 FormContainer 组件是什么样子的情况下,您可以简单地将 setter 函数(setSpaces从上面)作为道具传递给 FormContainer,并在提交表单时在 FormContainer 中调用它。以下是更新可能的样子:

const FormContainer = (props) => {
  const handleFormSubmit = () => {
    props.setSpaces({
      space5: {id: 5, name: "John Doe", classTaken: "Level 3", reserved: true, form: false}
    });
  };
  ...
}

这将更新spacesParkingLot 状态下空间 5 的数据,而不会影响任何其他空间数据。我已经spaces从数组更改为对象,因为useObjectState期望数据类似于setState经典组件中的数据。


推荐阅读