React 动态创建的 child 组件未收到新道具

React dynamically created child component not receiving new props

我正在尝试遵循 React 的 "Stateless children, stateful parent" 思想,它运行得很好......直到我开始动态创建 children,也就是说。

这是我的代码的简化版本(CoffeeScript + JSX),它说明了我的困境:

@FormBlock = React.createClass
  getInitialState: ->
    fields: [], editMode: false

  toggle: ->
    @setState editMode: !@state.editMode

  addChild: ->
    child = `<EditableText key={Date.now()} text="FAILS" editMode={this.state.editMode}/>`
    items = @state.fields.concat child
    @setState fields: items

  render: ->
    `<div>
        <a onClick={this.toggle}>Change Mode</a><br/>
        <a onClick={this.addChild}>Add Child</a><br/>
        <EditableText text="WORKS" editMode={this.state.editMode}/><br/>
        {this.state.fields}
    </div>`


@EditableText = React.createClass
  render: ->
    if @props.editMode
      `<input className="editable" defaultValue={this.props.text}/>`
    else
      `<span className="editable">{this.props.text}</span>`

在此示例中,组件 <FormBlock> 最初将不包含 fields 及其 editMode=false。当点击Change Mode按钮将editMode更改为true时,<EditableText>组件的内容将从<span>更改为<input>,这样用户可以对其进行更改。

这对 <FormBlock>render 方法(即 <EditableText text="WORKS".../>)中包含的虚拟组件非常有效,但这对 children 无效。我已经测试过,在创建时,每个 <EditableText> 类型的 child 都会收到其初始 props,但是当 state.editMode 被修改时,所有 children 都会保留不变(我已经验证 componentWillReceiveProps 不会在 children 上触发,但会在虚拟元素上触发)。

我无计可施地试图解决这个问题。请帮忙!!!

您的问题是调用EditableText 的结果保存在组件状态中。如果您想根据状态动态渲染子组件,请改为在 render 方法中执行:

@FormBlock = React.createClass
  getInitialState: ->
    fields: [], editMode: false

  toggle: ->
    @setState editMode: !@state.editMode

  addChild: ->
    items = @state.fields.concat {}
    @setState fields: items

  render: ->
    `<div>
        <a onClick={this.toggle}>Change Mode</a><br/>
        <a onClick={this.addChild}>Add Child</a><br/>
        <EditableText text="WORKS" editMode={this.state.editMode}/><br/>
        { this.state.fields.map @renderChild }
    </div>`

    renderChild: ->
        `<EditableText
            key={Date.now()}
            text="FAILS"
            editMode={this.state.editMode}/>`