React:具有相同事件处理程序的多个组件:尝试仅更改被单击组件的状态,而不更改所有其他组件的状态
React: multiple components with the same event handler: trying to change the state of only the component which was clicked and not of all the others
我是 React 的新手,必须完成一项特定的任务,其中我的应用程序的所有逻辑都在单个 parent 组件中,而 child 组件仅接收一些道具。但是,在 child 中不应该有任何逻辑或几乎没有逻辑。
我有一个由 25 个单元格组成的网格 (parent component),每个单元格 (child component ) 可以是打开或关闭。将每个细胞想象成一盏开或关的灯。
在我的 parent 组件中,我渲染了单元格组件 25 次。每次每个单元格有:
- 一把钥匙
- 一个id
- 一个状态(开启或关闭随机分配)
- 点击事件
在我的 child 组件中,当点击事件被触发时, child 组件 return 到 parent 它的 id 和它的状态(开或关)
我想达到的目标:
在我的 parent 组件中,我希望能够检测到哪个 child 被点击,并且只更改被点击的 child 的状态。
到目前为止我得到了什么:
尽管 parent 接收到被点击的 child 的 ID 和状态,当我通过 setState 更改状态时,所有 children 都会受到影响。
这是我的 parent 组件的片段:
import React, { Component } from 'react';
import GridSquare from './GridSquare';
import { randomlyLit, cellIdentifier } from '../helpers/helperFuns.js';
let nums = []
cellIdentifier(nums, 25)
class GridContainer extends Component {
static defaultProps = {
gridSize: 25
};
constructor(props) {
super();
this.state = {
cellID: nums,
hasWon: false,
lightStatus: Array.from({ length: 25 }, () => randomlyLit()),
};
this.changeValue = this.changeValue.bind(this);
}
changeValue(id, value) {
console.log(id, value);
this.setState(st => ({
// let result = st.cellID.filter(c => c===id)
// if(result){
// st.value = !value;
// }
lightStatus : !value
})
)
}
render() {
return (
<div>
<h1 className="neon">
Light <span className="flux">Out</span>
</h1>
<div className="GridContainer">
{this.state.cellID.map((el, i) =>(
<GridSquare key={this.state.cellID[i]} id={this.state.cellID[i]} lit={this.state.lightStatus[i]} click={this.changeValue}/>
))}
</div>
</div>
);
}
}
export default GridContainer;
这是我的 child 组件的片段:
import React, {Component} from 'react';
class GridSquare extends Component {
constructor(props){
super(props);
this.handleClick= this.handleClick.bind(this)
}
handleClick(){
this.props.click( this.props.id, this.props.lit);
}
render() {
const squareClasses = {
'GridSquareOn': this.props.lit === true,
'GridSquareOff': this.props.lit === false,
'GridSquare': true,
}
function classNames(squareClasses) {
return Object.entries(squareClasses)
.filter(([key, value]) => value)
.map(([key, value]) => key)
.join(' ');
}
const myClassName = classNames(squareClasses)
return(
<div className={myClassName} onClick={this.handleClick}>
</div>
)
}
}
export default GridSquare;
我的 app.js 只渲染 parent 组件,没有别的:
import GridContainer from './components/GridContainer.jsx'
import './style/App.css';
import './style/GridContainer.css';
import './style/GridSquare.css';
function App() {
return (
<div className="App">
<GridContainer />
</div>
);
}
export default App;
提前感谢您的帮助!
changeValue(id, value) {
console.log(id, value);
this.setState(st => ({
// let result = st.cellID.filter(c => c===id)
// if(result){
// st.value = !value;
// }
lightStatus : !value
})
您的更改值函数正在使用错误的值更新状态。
lightStatus
的初始值是一个布尔值数组(假设 randomlyLit
函数将 return 一个布尔值。
当您单击其中一个单元格时,lightStatus
会更新为 false
的值而不是数组。
要解决此问题,请按单击单元格的索引搜索整个 lightStatus
数组,并使用 Array.slice
.
更新该特定索引处的布尔值
如何优化
而不是每次都遍历整个数组来更新单元格的lightStatus
。您可以将值保存在 Object
.
中
如果我可以像这样更新 changeValue
中的状态呢?
this.setState((st) => {
return {
...st,
lightStatus: { ...st.lightStatus, [id]: value } // Direct update without traversing through array
}
});
lightStatus
可用于在 cellID
中的单元 ID 及其对应的状态布尔值之间形成“映射”。
我是 React 的新手,必须完成一项特定的任务,其中我的应用程序的所有逻辑都在单个 parent 组件中,而 child 组件仅接收一些道具。但是,在 child 中不应该有任何逻辑或几乎没有逻辑。 我有一个由 25 个单元格组成的网格 (parent component),每个单元格 (child component ) 可以是打开或关闭。将每个细胞想象成一盏开或关的灯。 在我的 parent 组件中,我渲染了单元格组件 25 次。每次每个单元格有:
- 一把钥匙
- 一个id
- 一个状态(开启或关闭随机分配)
- 点击事件
在我的 child 组件中,当点击事件被触发时, child 组件 return 到 parent 它的 id 和它的状态(开或关)
我想达到的目标:
在我的 parent 组件中,我希望能够检测到哪个 child 被点击,并且只更改被点击的 child 的状态。
到目前为止我得到了什么:
尽管 parent 接收到被点击的 child 的 ID 和状态,当我通过 setState 更改状态时,所有 children 都会受到影响。
这是我的 parent 组件的片段:
import React, { Component } from 'react';
import GridSquare from './GridSquare';
import { randomlyLit, cellIdentifier } from '../helpers/helperFuns.js';
let nums = []
cellIdentifier(nums, 25)
class GridContainer extends Component {
static defaultProps = {
gridSize: 25
};
constructor(props) {
super();
this.state = {
cellID: nums,
hasWon: false,
lightStatus: Array.from({ length: 25 }, () => randomlyLit()),
};
this.changeValue = this.changeValue.bind(this);
}
changeValue(id, value) {
console.log(id, value);
this.setState(st => ({
// let result = st.cellID.filter(c => c===id)
// if(result){
// st.value = !value;
// }
lightStatus : !value
})
)
}
render() {
return (
<div>
<h1 className="neon">
Light <span className="flux">Out</span>
</h1>
<div className="GridContainer">
{this.state.cellID.map((el, i) =>(
<GridSquare key={this.state.cellID[i]} id={this.state.cellID[i]} lit={this.state.lightStatus[i]} click={this.changeValue}/>
))}
</div>
</div>
);
}
}
export default GridContainer;
这是我的 child 组件的片段:
import React, {Component} from 'react';
class GridSquare extends Component {
constructor(props){
super(props);
this.handleClick= this.handleClick.bind(this)
}
handleClick(){
this.props.click( this.props.id, this.props.lit);
}
render() {
const squareClasses = {
'GridSquareOn': this.props.lit === true,
'GridSquareOff': this.props.lit === false,
'GridSquare': true,
}
function classNames(squareClasses) {
return Object.entries(squareClasses)
.filter(([key, value]) => value)
.map(([key, value]) => key)
.join(' ');
}
const myClassName = classNames(squareClasses)
return(
<div className={myClassName} onClick={this.handleClick}>
</div>
)
}
}
export default GridSquare;
我的 app.js 只渲染 parent 组件,没有别的:
import GridContainer from './components/GridContainer.jsx'
import './style/App.css';
import './style/GridContainer.css';
import './style/GridSquare.css';
function App() {
return (
<div className="App">
<GridContainer />
</div>
);
}
export default App;
提前感谢您的帮助!
changeValue(id, value) {
console.log(id, value);
this.setState(st => ({
// let result = st.cellID.filter(c => c===id)
// if(result){
// st.value = !value;
// }
lightStatus : !value
})
您的更改值函数正在使用错误的值更新状态。
lightStatus
的初始值是一个布尔值数组(假设 randomlyLit
函数将 return 一个布尔值。
当您单击其中一个单元格时,lightStatus
会更新为 false
的值而不是数组。
要解决此问题,请按单击单元格的索引搜索整个 lightStatus
数组,并使用 Array.slice
.
如何优化
而不是每次都遍历整个数组来更新单元格的lightStatus
。您可以将值保存在 Object
.
如果我可以像这样更新 changeValue
中的状态呢?
this.setState((st) => {
return {
...st,
lightStatus: { ...st.lightStatus, [id]: value } // Direct update without traversing through array
}
});
lightStatus
可用于在 cellID
中的单元 ID 及其对应的状态布尔值之间形成“映射”。