英文:
How to change state of multiple React children?
问题
以下是翻译好的内容:
<SidebarOption />
和 <SideBarContainers />
分别是具有名为 open
的状态的项目,当它们被点击时会突出显示,并且它们位于 <SidebarItemList />
内。
<SidebarOption id="1" name="Startsida: Fjärrvärmenät" />
<SidebarOption id="2" name="Startsida: Användare" />
<SideBarContainers id="3" name="Allmänt"
options={[
"Senaste uppdaterad", "Visa Pluginmoduler", "Öppna Arkivet", "Personliga inställningar",
"Regionala inställningar", "Om Driftportalen"
]}/>
<SideBarContainers id="4" name="Planering" notPressAble={[0, 6, 11]}
options={[
"Aktiviteter:", "+ Ny Aktivitet", "Visa Alla Öppna", "Visa Försenat", "Visa Alla Stängda", "Visa Alla Kategoriserat",
"Att göra:", "+ Ny Att göra", "Visa Alla Öppna", "Visa Alla Stängda", "Visa Alla Kategoriserat",
"Personal planering:", "+ Ny post", "Visa Alla enkel"
]} />
</SideBarItemList>
下面是 <SideBarItemList />
类,我想要更改项目的 open
值,以便如果一个项目被突出显示,而另一个项目被按下,我希望所有其他项目的状态 open
都设置为 false
,以便只有一个项目的状态 open
可以设置为 true
。问题是项目的状态 open
似乎不可扩展,我该怎么办?
我的错误:无法添加属性 open,对象不可扩展
class SideBarItemList extends Component{
constructor(props){
super(props);
this.state ={
sidebarItems: null
};
}
static getDerivedStateFromProps(props, state){
return{
sidebarItems: props.children
};
}
handleItems = () => {
let openNumber = null;
for(let x = 0; x < this.state.sidebarItems.length; x++)
{
if(this.state.sidebarItems[x].open = true)
{
openNumber = x;
}
this.state.sidebarItems[x].open = false;
}
this.state.sidebarItems[openNumber].open = true;
}
render(){
return(
<div onClick={this.handleItems}>
{this.state.sidebarItems}
</div>
)
}
}
export default SideBarItemList;
以下是 <SideBarConatiners />
的脚本,希望能够澄清:
import classes from "../../layout/Sidebar.module.css";
import { Link } from "react-router-dom";
class SidebarOption extends Component{
constructor(props){
super(props);
this.state = {
open: false,
}
}
setOpen = () => {
this.setState(prevState => {
return {
open: !prevState.open
}
})
}
setStates = () => {
this.setOpen()
}
render(){
return (
<div>
<Link to={this.props.link}>
<button
className={this.state.open ? classes.dropdownbtnopen: classes.dropdownbtn}
onClick={this.setStates}>{this.props.name}
</button>
</Link>
</div>
)
}
}
export default SidebarOption;
英文:
Down below is <SidebarOption />
and <SideBarConatiners />
these are both items that have a state called open
to highlight them whenever they have been clicked and they are inside the <SidebarItemList />
<SideBarItemList>
<SidebarOption id="1" name="Startsida: Fjärrvärmenät" />
<SidebarOption id="2" name="Startsida: Användare" />
<SideBarContainers id="3" name="Allmänt"
options={[
"Senaste uppdaterad", "Visa Pluginmoduler", "Öppna Arkivet", "Personliga inställningar",
"Regionala inställningar", "Om Driftportalen"
]}/>
<SideBarContainers id="4" name="Planering" notPressAble={[0, 6, 11]}
options={[
"Aktiviteter:", "+ Ny Aktivitet", "Visa Alla Öppna", "Visa Försenat", "Visa Alla Stängda", "Visa Alla Kategoriserat",
"Att göra:", "+ Ny Att göra", "Visa Alla Öppna", "Visa Alla Stängda", "Visa Alla Kategoriserat",
"Personal planering:", "+ Ny post", "Visa Alla enkel"
]} />
</SideBarItemList>
Down below is the <SideBarItemList />
class, i want to change the open value of the items soo that if one item is higlighted and another item is pressed i want all the other items to set the state open
to false
so that only one item state open
can be set to true
the problem is that the items state open
does not seem to be extensible what can i do about this?
my error: Cannot add property open, object is not extensible
import { Component } from "react";
class SideBarItemList extends Component{
constructor(props){
super(props);
this.state ={
sidebarItems: null
};
}
static getDerivedStateFromProps(props, state){
return{
sidebarItems: props.children
};
}
handleItems = () => {
let openNumber = null;
for(let x = 0; x < this.state.sidebarItems.length; x++)
{
if(this.state.sidebarItems[x].open = true)
{
openNumber = x;
}
this.state.sidebarItems[x].open = false;
}
this.state.sidebarItems[openNumber].open = true;
}
render(){
return(
<div onClick={this.handleItems}>
{this.state.sidebarItems}
</div>
)
}
}
export default SideBarItemList;
Script below of <SideBarConatiners />
added to hopefully clarify
import React, {Component} from "react";
import classes from "../../layout/Sidebar.module.css"
import { Link } from "react-router-dom";
class SidebarOption extends Component{
constructor(props){
super(props);
this.state = {
open: false,
}
}
setOpen = () => {
this.setState(prevState => {
return {
open: !prevState.open
}
})
}
setStates = () => {
this.setOpen()
}
render(){
return (
<div>
<Link to={this.props.link}>
<button
className={this.state.open ? classes.dropdownbtnopen: classes.dropdownbtn}
onClick={this.setStates}>{this.props.name}
</button>
</Link>
</div>
)
}
}
export default SidebarOption;
答案1
得分: 0
您可以使用 cloneElement(element, props)
来添加或覆盖子元素的属性值 文档。
您需要更改 SideBarItemList
的实现以跟踪本地状态中选定的子元素,并在状态更改时重新渲染并向所选的子元素提供 isSelected: true
,对其他所有子元素提供 isSelected: false
(或不提供)。
另一种选择(我不建议这样做)是以这样的方式实现所有子元素,以提供一种命令式接口(通过 forwardRef
和 useImperativeHandle
)允许像 child_37.collapse()
和 child_03.expand()
这样的方法调用。
您的实现可以看起来像这样:
export const SideBarItemList = ({ children }) => {
const [selected, setSelected] = useState();
return (
<ul>
{
React.Children.map(children, (child, index) => (
<li onClick={() => setSelected(index)}>
{React.cloneElement(child, { isOpen: index === selected })}
</li>
))
}
</ul>
);
};
英文:
You can add or override prop values for children with cloneElement(element, props)
doc.
You would need to change your implementation of SideBarItemList
to track in local state which child element is selected, and whenever the state changes you would re-render and provide isSelected: true
to the one selected child element and isSelected: false
(or nothing) to all others.
An alternative (I don't recommend here) is to implement all children in such a way as to offer an imperative interface (via forwardRef
and useImperativeHandle
) that would allow a method call like child_37.collapse()
and child_03.expand()
.
Your implementation could look like this:
export const SideBarItemList = ({ children }) => {
const [selected, setSelected] = useState();
return (
<ul>
{
React.Children.map(children, (child, index) => (
<li onClick={() => setSelected(index)}>
{React.cloneElement(child, { isOpen: index === selected })}
</li>
))
}
</ul>
);
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论