我正在尝试创建一个功能来轻松隐藏/显示所有项目(子组件(。通过使用useState
我可以设置是否隐藏/显示所有项目。通过使用useEffect
我可以切换隐藏/显示的项目。我在访问子组件中的 props 以确定项目是否已扩展时遇到问题。我希望我能更好地解释这一点,但希望这个编码示例能描绘出更好的画面。
索引.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);
项目.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;
代码沙盒
要复制我当前的错误,请单击任何"+ 显示项目",然后单击"全部隐藏"。它不会隐藏所有内容,但是单击"全部显示",然后"全部隐藏"将隐藏所有内容。
您面临此问题是因为您的父组件实际上有三种可能的状态:
- 全部展开
- 全部倒塌
- 既不展开也不折叠
为了反映第三种状态,您可以使用 null/undefined(并将资源库向下传递到子组件中(。
此处更新了示例:https://codesandbox.io/s/competent-villani-i6ggh
由于您正在顶层处理手风琴的扩展状态,因此我建议您将扩展状态和"切换器"传递给您的项目。index.js
将处理逻辑,您的Item
组件将是表示性的。
这是你的CodeSandbox的一个分支。
它看起来不太好,可能项目状态和切换可以(并且可能应该(移动到其他地方(例如,使用useReducer
钩子的单独减速器(
如果您计划动态创建这些组件,IMO 这是最简单的方法。
如果你仍然想走自己的路,你可以将Item
重构为类组件并使用 Refs 来获取它们的当前状态,但我不推荐这种方法。
希望这有帮助!
这是一个代码和沙盒,从你的分叉:
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"属性进行更新
(请参阅顶部粘贴的代码沙箱中的完整代码(