首页 > 解决方案 > ReactJS 类组件使用 contenteditable 元素渲染 array.map

问题描述

我遇到了一个无法调试的有趣问题。

目标

在一个类组件上,在 render 函数内部,遍历一个对象数组,state使用this.state.items.map((item, index) => {})并返回一个contentEditable段落元素。

在每个contentEditable段落元素上,监听onKeyUp事件。如果使用的键e.which是 enter (13) 键,则this.state.items使用被键控元素的索引添加一个新项目,以便在该索引之后使用splice.

看到预期的结果?

不,新添加的项目在渲染时被放在循环的末尾。

重现的示例情况和步骤:

  1. P在第一个元素中键入“test1”
  2. 点击回车(P创建并聚焦一个新元素)
  3. P在第二个新创建的元素中键入“test2”
  4. 重新关注第一个P元素,通过 shift+tab 或单击
  5. 点击进入
  6. 查看观察到的结果:P创建并聚焦了一个新元素,但它位于列表的末尾,而不是预期的位置,位于“test1”和“test2”P元素之间

这是我到目前为止的代码:

class MyComponent extends React.Component {
    constructor(props) {
        super(props)

        this.state = {
            items: [this.paragraphTemplate()]
        }
    }

    render() {
        return (
            <section>
                <div>
                    {this.state.items.map((item, index) => {
                        return <p ref={item.ref} 
                                  key={index}
                                  contentEditable 
                                  suppressContentEditableWarning 
                                  onKeyUp={e => this.handleParagraphKeyUp(e, index, item)}></p>
                    })}
                </div>
            </section>
        )
    }

    handleParagraphKeyUp = (e, index, item) => {
        if (e.which === 13) {
            let addition = this.paragraphTemplate()

            this.setState(state => {
                state.items.splice(index + 1, 0, addition)

                return {
                    blocks: state.items
                }
            }, () => {
                addition.ref.current.focus()

                /* clear out the br and div elements that the browser might auto-add on "enter" from the element that was focused when the "enter" key was used */
                this.state.items[index].ref.current.innerHTML = this.state.items[index].ref.current.innerHTML.replace(/<br\s*[\/]?>/gi, '').replace(/<[\/]?div>/gi, '')
            })

            return false
        }
    }

    paragraphTemplate = () => {
        return {
            ref: React.createRef()
        }
    }
}

export default MyComponent

这是一个带有上面代码的jsfiddle

如果您采取上述步骤,您将看到我遇到的问题。

如果您需要任何进一步的信息,请告诉我,提前致谢!

PS如果我可以对代码进行任何改进,请告诉我。我在 React 中工作了很短的时间,并且希望得到任何关于如何使它更好/更清洁的反馈。

更新

添加key={index}P元素中。注意:这并不反映任何答案,它只是为了与 ReactJS 列表呈现保持一致而添加的。

标签: javascriptreactjsjsxcontenteditable

解决方案


要呈现项目列表,React 需要 key 来跟踪元素,请参见:https ://reactjs.org/docs/lists-and-keys.html

这是您更新的小提琴,可以正常工作..

<p ref={item.ref} 
   key={item.id}
   contentEditable 
   suppressContentEditableWarning 
   onKeyUp={e => this.handleParagraphKeyUp(e, 

推荐阅读