当我在父组件中通过 useState 设置状态时,我传递给的子组件中的道具是未定义的

When I set state via useState in parent component, my props in the child I'm passing down to are undefined

我有一个父组件列表,它有一个种子文件中的对象数组。我只想在页面加载时加载 14 个对象中的前 9 个。

const Listings = () => {
  const [ listingsData, setListings] = useState(listings);

  const [ homesDisplayed , setDisplayNumber ] = useState(listingsData.slice(0, 9));
  const homes = homesDisplayed.map((home, index) => (
    <div className="col xl4" key={index}>
      <HomeListingCard 
        name={home.homeName}
        imageUrl={home.imageURL}
        beds={home.beds}
        baths={home.baths}
        isMultiSection={home.isMultiSection}
        sqft={home.sqft}
        startingPrice={home.startingPrice}
      />
    </div>
  ));

  return (
    <div>
      <div className="row">
        <div className="listings-subheader">
          <h3 className="left available-homes">{`${listingsData.length} `}homes available</h3>
          <div className="right">
            <SortBy />
          </div>
        </div>
      </div>
      <div className="row">
        {homes}
      </div>
      <div className="row">
        <LoadListings listings={listingsData} homesDisplayed={homes} setDisplayNumber={setDisplayNumber} />
      </div>
    </div>
  )
}

export default Listings;

我使用 const [ homesDisplayed , setDisplayNumber ] = useState(listingsData.slice(0, 9)); 将 9 个对象的数组设置为 state。

这很好用。

然后我尝试将我的状态作为道具传递给子组件,如下所示:

<LoadListings listings={listingsData} homesDisplayed={homes} setDisplayNumber={setDisplayNumber} />

当页面最初加载时,这些道具有数据。但是当我在 <LoadListings /> 子组件中点击一个按钮到 console.log(props) 时,我的数据都是未定义的。

<LoadListings /> 看起来像:

const LoadListings = (props) => {
    const updateListings = (props) => {
        console.log(props.homes);
        // props.setDisplayNumber(...props.homesDisplayed, props.listings.slice(9, 12));
    }

    return (
        <button onClick={updateListings}>Load More</button>
    )
}

我的目标是单击按钮并updateLIstings从原来的 14 数组中再拼接 3 个,然后像这样将它们添加到 homeDisplayed 数组中

const updateListings = (props) => {
        props.setDisplayNumber(...props.homesDisplayed, props.listings.slice(9, 12));
}

但是props.homesDisplayed——以及所有的道具——都是未定义的。

谢谢。

发生这种情况是因为您没有实际上将您的道具传递给updateListings函数。

如果仔细查看函数声明,您会注意到您已将 props 定义为参数。然后,在 onClick 属性上,您实际上并没有将任何东西 传递给 函数。

考虑 updateListings 函数的作用域...您实际上不需要传递任何东西,因为它已经可以从父作用域访问 props。不幸的是,通过第二次将 props 定义为函数参数,您正在隐藏更高范围的 props(有效地告诉函数忽略它)。

如果您更新 updateListings 以省略 props 参数,它 应该 工作(除非您的代码中存在任何其他问题)。

const updateListings = (props) => {
  console.log(props.homes);
  props.setDisplayNumber(...props.homesDisplayed, props.listings.slice(9, 12));
}

旁注:您可能只想存储要显示的项目数,而不是将切片数据存储在状态中。这样,您就可以通过在渲染本身中执行切片来简化一切,而不是对状态中的数据进行推理。例如:

const [ listingsData, setListings] = useState(listings);

// Store number to display
const [ homesDisplayed , setDisplayNumber ] = useState(9);

// Slice before map, which'll update every time you increment `homesDisplayed
const homes = homesDisplayed.slice(0, homesDisplayed).map((home, index) => (
  <div className="col xl4" key={index}>
    <HomeListingCard 
      name={home.homeName}
      imageUrl={home.imageURL}
      beds={home.beds}
      baths={home.baths}
      isMultiSection={home.isMultiSection}
      sqft={home.sqft}
      startingPrice={home.startingPrice}
    />
  </div>
));

另一个旁注:通常你会想要命名你的 [state, setState] val/updater 始终遵循 varName, setVarName 的约定。这样,当您稍后尝试调和什么控制什么时,reader(和您!)就不会那么困惑了。

所以我建议将 [homesDisplayed, setDisplayNumber] 更改为 [displayNumber, setDisplayNumber]