反应:从状态中删除动态输入,然后重新呈现

时间:2020-10-08 21:05:58

标签: javascript arrays reactjs state slice

我无法调试这种情况。我正在尝试从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>
    )
}

2 个答案:

答案 0 :(得分:1)

使用索引作为组件的键是一种不好的做法,尤其是当它正在更改的列表时。密钥应该是组件的唯一标识符。

如果您的控件没有唯一的标识符,则可以基于时间戳和某种uuid创建一个标识符,并将其存储在状态中,并且始终且始终仅引用一个控件元素。 / p>

想象一下,您有1个输入元素的值为TextInput 1的情况。然后,从中添加另一个输入,它会继承其键。现在您已经破坏了影子DOM,因为您引用的是新输入而不是旧的输入,因为key = {0}的输入的值为TextInput 1,但这不是您所期望的,因为您要引用另一输入

答案 1 :(得分:0)

此行有问题:

<Fragment key={key}>

由于您正在使用数组的索引来呈现这些Fragments,所以对帐失败length次,并且“最后一个元素”被删除。我真的建议您观看this video,非常有用。您应该使用唯一的标识符。