javascript - 如何将道具传递给父级(Material-UI React)
问题描述
所以我到处寻找解决方案,但没有运气。
我正在尝试将父 React 组件this.state.nextID
作为属性传递给子组件。但是,当我尝试访问子项中的该属性时,它为空。我正在使用 Material-UI 进行反应,我认为问题出在withStyles
功能上,因为当我检查页面的源时,我看到了节点key
上的属性。withStyles(ServerBlock)
但是该节点有一个子节点,即ServerBlock
,没有key
属性。我究竟做错了什么?
ConfigBlock.js
class ConfigBlock extends Component {
constructor () {
super()
this.state = {
children: [],
nextID: 0
}
this.handleChildUnmount = this.handleChildUnmount.bind(this);
}
handleChildUnmount = (key) => {
console.log(key)
this.state.children.splice(key, 1);
this.setState({children: this.state.children});
}
addServerBlock() {
this.state.children.push({"id": this.state.nextID, "obj": <ServerBlock unmountMe={this.handleChildUnmount} key={this.state.nextID} />})
this.setState({children: this.state.children})
this.state.nextID += 1
}
addUpstreamBlock() {
this.state.children.push({"id": this.state.nextID, "obj": <UpstreamBlock unmountMe={this.handleChildUnmount} key={this.state.nextID} />})
this.setState({children: this.state.children})
this.state.nextID += 1
}
render () {
const {classes} = this.props;
return (
<div className={classes.container}>
<Card className={classes.card}>
<CardContent>
<Typography className={classes.title} color="primary">
Config
</Typography>
<div>
{this.state.children.map((child, index) => {
return (child.obj);
})}
</div>
</CardContent>
<CardActions>
<Button variant="contained" color="primary" className={classes.button} onClick={ this.addServerBlock.bind(this) }>
Server
<AddIcon />
</Button>
<Button variant="contained" color="primary" className={classes.button} onClick={ this.addUpstreamBlock.bind(this) }>
Upstream
<AddIcon />
</Button>
</CardActions>
</Card>
</div>
);
}
}
ConfigBlock.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(ConfigBlock);
ServerBlock.js
class ServerBlock extends Component {
constructor (props) {
super(props)
this.state = {
children: []
}
}
addServerBlock() {
this.state.children.push(<NginxEntry/>)
this.setState({children: this.state.children})
}
deleteMe = () => {
this.props.unmountMe(this.props.key);
}
render () {
const {classes} = this.props;
return (
<div className={classes.container}>
<Card className={classes.card}>
<CardContent>
<Typography className={classes.title} color="primary">
Server
</Typography>
</CardContent>
<CardActions>
<Button variant="contained" color="primary" className={classes.button} onClick={() => { console.log('onClick'); }}>
Key/Value
<AddIcon />
</Button>
<Button variant="contained" color="primary" className={classes.button} onClick={() => { console.log('onClick'); }}>
Location
<AddIcon />
</Button>
<Button variant="contained" color="primary" className={classes.button} onClick={() => { console.log('onClick'); }}>
Comment
<AddIcon />
</Button>
<Button variant="contained" color="primary" className={classes.button} onClick={ this.deleteMe }>
<DeleteIcon />
</Button>
</CardActions>
</Card>
</div>
);
}
}
ServerBlock.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(ServerBlock);
解决方案
key
是一个特殊的 React 属性,它不是一个道具,即孩子永远无法访问它的值。如果孩子需要使用该值,请通过另一个道具(以及通过键)提供它,例如
<ServerBlock
unmountMe={this.handleChildUnmount}
key={this.state.nextID}
id={this.state.nextID}
/>
...除此之外,您的代码非常不寻常。您不应该直接改变状态(您应该始终使用setState
),并且您通常不会将整个组件存储在您的状态中。正如深思熟虑的那样,这里是您的ConfigBlock
组件的替代(未经测试)实现,它使用setState
并稍微改变了一些逻辑:
class ConfigBlock extends Component {
constructor () {
super()
this.state = {
nextID = 0,
children: [],
}
this.handleChildUnmount = this.handleChildUnmount.bind(this);
// bind this function once here rather than creating new bound functions every render
this.addBlock = this.addBlock.bind(this)
}
handleChildUnmount = (key) => {
console.log(key)
this.setState(state => {
return {
// `state.children.splice(key, 1)`, aside from mutating the state,
// will not work as expected after the first unmount as the ids and
// array positions won't stay aligned
children: state.children.slice().filter(child => child.id !== key)
}
})
}
// Consolidate the two addBlock functions, given we're determining the type
// of component to render in the render function.
addBlock(blockType) {
this.setState(state => {
return {
children: [...state.children, { id: state.nextID, type: blockType }]
nextID: state.nextID + 1
}
})
}
render () {
const {classes} = this.props;
return (
<div className={classes.container}>
<Card className={classes.card}>
<CardContent>
<Typography className={classes.title} color="primary">
Config
</Typography>
<div>
{this.state.children.map(child => {
// determine the component to render here rather than in the handlers
if (child.type === 'server') {
return <ServerBlock key={child.id} id={child.id} unmountMe={this.handleChildUnmount(child.id)} />
} else if (child.type === 'upstream') {
return <UpstreamBlock key={child.id} id={child.id} unmountMe={this.handleChildUnmount(child.id)} />
}
})}
</div>
</CardContent>
<CardActions>
<Button variant="contained" color="primary" className={classes.button} onClick={this.addBlock('server')}>
Server
<AddIcon />
</Button>
<Button variant="contained" color="primary" className={classes.button} onClick={this.addBlock('upstream')}>
Upstream
<AddIcon />
</Button>
</CardActions>
</Card>
</div>
);
}
}
推荐阅读
- alert - (Pine Editor) 斐波那契指标警报
- c++ - 需要帮助追踪访问错误违规
- eslint - 用于 mobx 的 Eslint 插件,如果您在没有观察者的情况下使用商店时会发出警告
- javascript - 在嵌套数组javascript中分组对象列表
- elasticsearch - 如何修复“java.nio.file.NoSuchFileException:/sys/fs/cgroup/cpuacct/docker/8a06898d8e300771d98f9877d1aa61003fb456d57d98a3706c99/cpuacct.usage”
- azure-aks - Azure RBAC 和 AKS 未按预期工作
- python-3.x - PYQT 状态栏不更新
- c# - 无法在 C# 中使用 p/invoke 销毁任意窗口
- rust - 与 docs.rs 源代码比较时源代码不一致
- python - 找不到单词统计文件!HTTP 错误 404:在 ekphrasis 库中找不到