ReactJS class 组件渲染 array.map 使用 contenteditable 元素

ReactJS class component render array.map using contenteditable elements

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

目标

在 class 组件上,在渲染函数内部,使用 this.state.items.map((item, index) => {}) 和 return 迭代 state 中的对象数组 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 上面的代码。

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

如果您需要任何进一步的信息,请告诉我,在此先感谢!

P.S。如果我可以对代码进行任何改进,请告诉我。我已经在 React 中工作了很短的时间,并且希望收到有关如何制作它的任何反馈 better/cleaner。

已更新

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

要呈现项目列表,React 需要键来跟踪元素 看到这个:https://reactjs.org/docs/lists-and-keys.html

这是您更新后的 fiddle 工作..

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