【问题标题】:React: Removing dynamic input from state, rerenderReact:从状态中删除动态输入,重新渲染
【发布时间】:2021-01-23 23:28:13
【问题描述】:

我无法调试这种情况。我正在尝试从 API 提供的数组中删除索引。在检查其父级的道具更改后,我将其存储在父级状态中。这里一切都很好。我可以在父表单状态中存储任何道具更改。

父表单映射 templateData 中的所有内容,我确定它是什么类型,然后根据需要渲染组件。

删除按钮将始终仅位于 DynamicInputGroup 中,因此我通过道具将该功能向下传递。在 DynamicInputGroup 中,我需要映射从父级传递的数组,然后映射该数组中的对象以显示每个单独的输入。再次使用传递下来的道具来确定要渲染的输入,与父级相同。

这就是问题所在。当我单击删除时,假设索引 5 中的第 2 个,我看到该索引在状态中被删除,但呈现的是索引 5 被删除。我不确定如何解决这个问题。我已经完成了研究并阅读了密钥发挥作用?我试图将渲染函数中的变量设置为状态,以便刷新,但没有。最后一个索引总是被删除。哈!

父表单

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>
    )
}

【问题讨论】:

    标签: javascript arrays reactjs state slice


    【解决方案1】:

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

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

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

    【讨论】:

    • 试图想出一个唯一的 id 给他们。我在考虑对象的值,但可能存在非唯一值的实例
    • @Ryan uuid 是一种方法。您可以给它input-${Date.now()} 的密钥,然后在整个会话期间坚持使用该密钥。如果您需要持久保留此布局/逻辑,您也可以将该 uuid 存储到您的数据库中。
    • 我会将该键设置为 DynamicInputGroup 中的 Grid 吗?这就是我感到困惑的地方
    • 是的,地图功能中的第一个孩子,在您当前的情况下是网格。 Grid的子元素在对账阶段不会有混乱
    • 似乎将删除按钮移动到正确的地图也可以解决问题。但是将我的密钥重命名为唯一 ID 有效
    【解决方案2】:

    这行有问题:

    <Fragment key={key}>
    

    由于您使用数组的索引来呈现这些Fragments,因此协调失败length 次并且“最后一个元素”被删除。我真的会推荐观看this video,非常有帮助。您应该使用唯一标识符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-19
      • 2016-11-04
      • 2021-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-14
      相关资源
      最近更新 更多