接收道具时,React输入不会更新

时间:2016-09-21 17:21:44

标签: forms reactjs

修正

第一次渲染元素时添加此方法,它可以立即访问收到的props

componentDidMount() {
  if (typeof this.props.options.value !== "undefined")
    this.setState({value: this.props.options.value})
},

我有几个反应元素几乎按预期工作。我有一个视图与元素列表和模态视图来编辑它们。单击元素的编辑按钮时,元素将设置为所选状态,并显示模态形式(将元素作为prop传递)。

showUpdateForm(poiIndex) {
  this.setState({selectedPoi: this.state.pois[poiIndex]})
  $('#updatePoiModal').modal('show')
  console.log('shown')
},

...render()...
<UpdatePoiForm poi={this.state.selectedPoi} ref="updatePoiForm" successHandler={this.successUpdateHandler}/>

单击某个项目时,模态视图会正确显示,但不会显示传递的文本值;显示前一个选定元素中的元素(如果是单击的第一个元素,则显示空框)。这是模态视图的渲染方法:

render() {
  console.log('rendering')
  if(!this.props.poi)
    return null
  console.log(this.props.poi.name)
  var poi = this.props.poi

  var config = {
    url: `${context.apiUrl}user/pois/${poi.id}`,
    method: 'PUT',
    successMessage: 'El Punto de Interés fue actualizado',
    successHandler: this.successHandler,
    hideSubmitButton: true,
    fields: {
      name: {
        label: 'Nombre',
        type: 'text',
        value: this.props.poi.name
      },
      location: {
        label: 'Ubicación',
        type: 'text',
        display: false,
        value: this.props.poi.location
      },
      category_id: {
        label: 'Categoría',
        type: 'select',
        options: context.poi_categories.map((cat) => {
          return {value: cat.id, desc: cat.name}
        })
      }
    }
  }

  return (
    <div>
      <Row>
        <Col size="12">
          <Panel>
            <PanelBody>
              <FormComponent config={config} ref="form"/>
            </PanelBody>
          </Panel>
        </Col>
        <Col size="12">
          <Panel>
            <PanelHeading heading="Selecciona la ubicación" />
            <Map height="400px" ref="map_update_poi" zoom="15"/>
          </Panel>
        </Col>

      </Row>
    </div>
  )
}

以下是表单组件的render方法:

render() {
  elems = []
  count = 0

  for (var key in this.props.config.fields) {
    console.log(this.props.config.fields[key])
    var _type = this.props.config.fields[key].type
    var config = {
      key: count++,
      options: this.props.config.fields[key],
      ref: key,
      refName: key,
      fullWidth: this.props.config.fullWidth,
    }

    switch (_type) {
      case 'text':
        elems.push(<InputElement {...config}/>)
        break
      case 'select':
        elems.push(<SelectElement {...config}/>)
        break
      case 'multipleSelect':
        elems.push(<MultipleSelectElement {...config}/>)
        break
      case 'button':
        elems.push(<ButtonElement {...config}/>)
        break
      case 'switcher':
        elems.push(<SwitcherElement {...config}/>)
        break
      case 'timePicker':
        elems.push(<TimePickerElement {...config}/>)
        break
      case 'radio':
        elems.push(<RadioElement {...config}/>)
        break
      case 'autocomplete':
        elems.push(<AutoCompleteInputElement {...config}/>)
        break
    }
  }
  console.log(elems)

  return (
    <form action="#" className="form-horizontal">
      <div className="form-content">
        {elems}
        {!this.props.config.hideSubmitButton ? <div className="form-buttons">
          <div className="row">
            <div className="col-md-offset-3 col-md-9">
              <button type="submit" onClick={this.handleSave}
                      className="btn btn-blue btn-ripple">Crear</button>
            </div>
          </div>
        </div> : null}
      </div>
    </form>
  )
}

输入元素的render方法(为简洁而删除了变量声明,没有丢失):

render() {
  return (
    <div className={formClass} style={style}>
      <label className="control-label col-md-3">{this.props.options.label}</label>
      <div className={inputClass}>
        <div className="inputer">
          <div className="input-wrapper">
            <input ref={this.props.refName} type="text" className="form-control" onFocus={this.props.onFocus}
              placeholder={this.props.placeholder} value={this.state.value} onChange={this.handleChange}/>
          </div>
          {validationMsg}
        </div>
      </div>
    </div>
  )
}

最后,我在这里检查输入道具:

componentWillReceiveProps(nextProps) {
  console.log('input element', nextProps)
  if (typeof this.props.options.value !== "undefined")
    this.setState({value: this.props.options.value})
},

我在链的每个“停止”中添加了日志语句。模态视图正确显示元素,表单显示单击的最后一个元素的字符串,输入元素的props也显示最近单击元素的信息。但是,在呈现输入时,this.state.value为空(这是getInitialState()中给出的值)或前一个元素的值。根据日志的顺序,在渲染之前接收道具。虽然我理解状态更新不是立即的,如果渲染发生了,那么状态的改变应该再次触发渲染,这次使用正确的值,但它没有发生,我不明白为什么!

shown
list index 1
name Object { label="Nombre",  type="text"}
location Object { label="Ubicación",  type="text",  display=false}
category_id Object { label="Categoría",  type="select",  options=[2]}
[Object { key="0",  ref="name",  props={...},  more...}, Object { key="1",  ref="location",  props={...},  more...}, Object { key="2",  ref="category_id",  props={...},  more...}]
input props Object { options={...},  refName="name",  fullWidth=undefined}
render input null
input props Object { options={...},  refName="location",  fullWidth=undefined}componentWillReceiveProps    index.js (line 35220)
render input null
** At this point the new element is received **
** The objects didn't paste completely, but the correct values are 
   there this time. However, there is no output from componentWillReceiveProps **
new poi test02
rendering update form
update form test02
name Object { label="Nombre",  type="text",  value="test02"}
location Object { label="Ubicación",  type="text",  display=false,  more...}
category_id Object { label="Categoría",  type="select",  options=[2]}
[Object { key="0",  ref="name",  props={...},  more...}, Object { key="1",  ref="location",  props={...},  more...}, Object { key="2",  ref="category_id",  props={...},  more...}]
2 render input null
Object { category="Almacen",  category_id=1,  id=627,  more...}

编辑2: 现在只有第一次点击才会出现此问题。当我根据@ Radio-的建议替换this.props for nextProps时发生了。

1 个答案:

答案 0 :(得分:1)

componentWillReceiveProps中,将州设置为nextProps.options.value而不是this.props.options.value

componentWillReceiveProps(nextProps) {
  if (typeof nextProps.options.value !== "undefined")
    this.setState({value: nextProps.options.value})
},

如果它在第一次渲染时,componentWillReceiveProps没有被调用,那么你可以使用componentDidMount和this.props来实现相同的目标:

componentDidMount() {
   if (typeof this.props.options.value !== "undefined")
   this.setState({value: this.props.options.value})
}