使用挂钩从子组件访问道具/属性

时间:2019-09-25 04:15:23

标签: javascript reactjs react-hooks

我正在尝试创建一个功能,以轻松隐藏/显示所有项目(子组件)。通过使用useState,我可以设置是否隐藏/显示所有项目。通过使用useEffect,我可以切换隐藏/显示的项目。我在访问子组件中的道具时遇到问题,以确定某个项目是否已经扩展。我希望我能对此做更好的解释,但是希望这个编码示例可以画出更好的图片。

index.js

import React, { useState } from "react";
import ReactDOM from "react-dom";
import "semantic-ui-css/semantic.min.css";
import { Button } from "semantic-ui-react";
import Item from "./Item";

const Services = props => {
  const [allExpanded, setAllExpanded] = useState(false);

  return (
    <>
      <p>
        <Button onClick={() => setAllExpanded(false)} content="Hide all" />
        <Button onClick={() => setAllExpanded(true)} content="Show all" />
      </p>
      <p>
        <Item expanded={allExpanded} />
        <Item expanded={allExpanded} />
        <Item expanded={allExpanded} />
      </p>
    </>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<Services />, rootElement);

Item.js

import React, { useState, useEffect } from "react";
import { Accordion } from "semantic-ui-react";

const Item = props => {
  const [expanded, setExpanded] = useState(props.expanded);

  useEffect(() => {
    setExpanded(props.expanded);
  }, [props.expanded]);

  return (
    <Accordion styled>
      <Accordion.Title
        onClick={() => {
          setExpanded(!expanded);
        }}
      >
        <p>{expanded ? "- Hide Item" : "+ Show Item"}</p>
      </Accordion.Title>
      <Accordion.Content active={expanded}>Lorem ipsum...</Accordion.Content>
    </Accordion>
  );
};

export default Item;

CodeSandbox

要复制我当前的错误,请单击任何“ +显示项”,然后单击“全部隐藏”。它不会隐藏所有内容,但是单击“全部显示”,然后单击“全部隐藏”将隐藏所有内容。

3 个答案:

答案 0 :(得分:1)

您正面临此问题,因为您的父组件实际上具有三种可能的状态:

  • 全部展开
  • 全部折叠
  • 所有扩展或折叠都没有

要反映第三个状态,可以使用null / undefined(并将setter传递到子组件中)。

此处更新了示例:https://codesandbox.io/s/competent-villani-i6ggh

答案 1 :(得分:0)

由于您正在顶层处理手风琴的扩展状态,因此建议您将扩展状态和“切换器”传递给您的商品。 index.js将处理逻辑,而您的Item组件将是演示性的。

这是您的CodeSandbox的分支。

它看起来不太好,并且项目状态和切换可能(可能应该)移动到其他地方(例如,使用useReducer hook的单独的reducer)

如果您打算动态创建这些组件,那么IMO这是最简单的方法。

如果您仍然想走自己的路,可以将Item重构为类组件,并使用Refs来获取其当前状态,但是我不推荐方法。

希望这会有所帮助!

答案 2 :(得分:0)

这是从您的代码中分叉出来的一个代码和沙箱:

https://codesandbox.io/s/competent-wildflower-n0hb8

我更改了它,以免出现类似这样的情况:

let [allExpanded, setAllExpanded] = useState(true) 

您有类似这样的内容:

let [whichExpanded, setWhichExpanded] = useState({0: true, 1:true, 2: true})

然后,打开回调以展开/折叠所有按钮,您将得到:

<button onClick=()=>{
    let newState = {}
    for(let order in whichEpanded){
       newState[order] = false //change every key to false
    }
    setAllExpanded(newState)
}> hide all</button>

然后,我为您的物品传递了一个“订购”道具。 “ order”道具用作我传递的回调函数的参数,因此,当您单击每个项目时,它会更新whichExpanded状态,以切换该项目的可见性。

 // pass this to eac of the items:
 const setIndividualItemExpanded = order => {
    let newItemsExpandedState = { ...itemsExpanded };
    newItemsExpandedState[order] = !newItemsExpandedState[order];
    setItemsExpanded(newItemsExpandedState);
  };

每个项目组成部分:

  <Item
      expanded={itemsExpanded[0]} //is reading from the state
      order={0}
      setExpanded={setIndividualItemExpanded}
    />

然后,您可以从呈现的组件中删除useState,而只需使用“ setExpanded”道具进行更新

(请参阅粘贴在顶部的代码和框中的完整代码)