我无法调试这种情况。我正在尝试从API提供的数组中删除索引。在检查其父项的道具更改后,我将其存储在“父项”状态中。这里一切都很好。我可以将任何属性更改存储在“父表单”状态中。
父表单会映射 templateData 中的所有内容,然后确定其类型,然后根据需要呈现组件。
“删除”按钮将始终仅位于 DynamicInputGroup 中,因此我通过props向下传递了该功能。在 DynamicInputGroup 中,我需要映射从父级传递来的数组,然后映射该数组中的对象以显示每个单独的输入。再次使用传递的props确定要渲染的输入,与parent相同。
这是哪里出了问题。当我单击“删除”时,假设5中的索引2处于删除状态,但是呈现的状态是删除了索引5。我不确定该如何处理。我已经进行了研究,并阅读到有钥匙在起作用吗?我尝试将render函数中的变量设置为状态,以便其可以刷新,但是什么也没有。最后的索引总是被删除。死了!
父母表格
this.state = {
templateData: []
}
removeGroupItem = (index, inputName ) => {
let group = `${inputName}__group`
const newState = this.state;
if (index === -1) return;
newState.templateData[group].splice(index, 1);
console.log(newState) // THIS SHOWS CORRECT STATE
this.setState(newState);
}
render() {
return (
{Object.keys(this.state.templateData).map((name, key) => {
let data = { // SETTING inputType TO DISPLAY CORRECT COMPONENT }
return (
<Fragment key={key}>
{data.inputType == 'input' && <DynamicTextInput {...data} />}
{data.inputType == 'rtf' && <DynamicRTF {...data} />}
{data.inputType == 'img' && <DynamicImageUpload {...data} />}
{data.inputType == 'group' && <DynamicInputGroup {...data} removeGroupItem={this.removeGroupItem} />} // COMPONENT THAT HOLDS REMOVE BUTTON
</Fragment>
)
})}
)
}
DynamicInputGroup组件
this.state = {
value: []
}
componentDidMount() {
this.setState({ value: this.props.value })
}
componentDidUpdate(prevProps) {
if (this.props.value !== prevProps.value) {
this.setState({
value: this.props.value
})
}
}
render() {
return (
<Fragment>
<Typography>{this.props.inputName}</Typography>
{this.state.value.map((value, key) => {
return (
<span>
{Object.keys(value).map((input, index) => {
let data = { // SETTING inputType TO DISPLAY CORRECT COMPONENT }
return (
<Grid key={index}>
{data.inputType == 'input' && <DynamicTextInput {...data} />}
{data.inputType == 'rtf' && <DynamicRTF {...data} />}
{data.inputType == 'img' && <DynamicImageUpload {...data} />}
{data.inputType == 'group' && <DynamicInputGroup {...data} />}
</Grid>
)
})}
{key >= 1 ? <span onClick={() => this.props.removeGroupItem(key, this.props.inputName)}>remove</span> : ''}
</span>
)
})}
</Fragment>
)
}
然后,如果需要 DynamicTextInput
const DynamicTextInput = (props) => {
return (
<Grid>
<TextField
name={props.inputName} label={props.inputName} defaultValue={props.value}
size="small" variant="outlined" fullWidth multiline
/>
</Grid>
)
}
答案 0 :(得分:1)
使用索引作为组件的键是一种不好的做法,尤其是当它正在更改的列表时。密钥应该是组件的唯一标识符。
如果您的控件没有唯一的标识符,则可以基于时间戳和某种uuid创建一个标识符,并将其存储在状态中,并且始终且始终仅引用一个控件元素。 / p>
想象一下,您有1个输入元素的值为TextInput 1
的情况。然后,从中添加另一个输入,它会继承其键。现在您已经破坏了影子DOM,因为您引用的是新输入而不是旧的输入,因为key = {0}的输入的值为TextInput 1
,但这不是您所期望的,因为您要引用另一输入
答案 1 :(得分:0)
此行有问题:
<Fragment key={key}>
由于您正在使用数组的索引来呈现这些Fragments
,所以对帐失败length
次,并且“最后一个元素”被删除。我真的建议您观看this video,非常有用。您应该使用唯一的标识符。