[javascript] React 입력 defaultValue가 상태로 업데이트되지 않습니다.

반응으로 간단한 양식을 만들려고하는데 데이터가 양식의 defaultValue에 제대로 바인딩되는 데 어려움이 있습니다.

내가 찾고있는 동작은 다음과 같습니다.

  1. 내 페이지를 열 때 텍스트 입력 필드가 데이터베이스의 AwayMessage 텍스트로 채워 져야합니다. 이것이 “샘플 텍스트”입니다.
  2. 데이터베이스의 AwayMessage에 텍스트가없는 경우 이상적으로는 텍스트 입력 필드에 자리 표시자를 갖고 싶습니다.

그러나 지금은 페이지를 새로 고칠 때마다 텍스트 입력 필드가 비어 있습니다. (입력에 입력 한 내용이 제대로 저장되고 지속되지만) AwayMessage가 빈 개체 일 때 입력 텍스트 필드의 html이로드되지만 awayMessage가로드 될 때 새로 고쳐지지 않기 때문이라고 생각합니다. 또한 필드의 기본값을 지정할 수 없습니다.

명확성을 위해 일부 코드를 제거했습니다 (예 : onToggleChange).

    window.Pages ||= {}

    Pages.AwayMessages = React.createClass

      getInitialState: ->
        App.API.fetchAwayMessage (data) =>
        @setState awayMessage:data.away_message
        {awayMessage: {}}

      onTextChange: (event) ->
        console.log "VALUE", event.target.value

      onSubmit: (e) ->
        window.a = @
        e.preventDefault()
        awayMessage = {}
        awayMessage["master_toggle"]=@refs["master_toggle"].getDOMNode().checked
        console.log "value of text", @refs["text"].getDOMNode().value
        awayMessage["text"]=@refs["text"].getDOMNode().value
        @awayMessage(awayMessage)

      awayMessage: (awayMessage)->
        console.log "I'm saving", awayMessage
        App.API.saveAwayMessage awayMessage, (data) =>
          if data.status == 'ok'
            App.modal.closeModal()
            notificationActions.notify("Away Message saved.")
            @setState awayMessage:awayMessage

      render: ->
        console.log "AWAY_MESSAGE", this.state.awayMessage
        awayMessageText = if this.state.awayMessage then this.state.awayMessage.text else "Placeholder Text"
        `<div className="away-messages">
           <div className="header">
             <h4>Away Messages</h4>
           </div>
           <div className="content">
             <div className="input-group">
               <label for="master_toggle">On?</label>
               <input ref="master_toggle" type="checkbox" onChange={this.onToggleChange} defaultChecked={this.state.awayMessage.master_toggle} />
             </div>
             <div className="input-group">
               <label for="text">Text</label>
               <input ref="text" onChange={this.onTextChange} defaultValue={awayMessageText} />
             </div>
           </div>
           <div className="footer">
             <button className="button2" onClick={this.close}>Close</button>
             <button className="button1" onClick={this.onSubmit}>Save</button>
           </div>
         </div>

AwayMessage에 대한 내 console.log에 다음이 표시됩니다.

AWAY_MESSAGE Object {}
AWAY_MESSAGE Object {id: 1, company_id: 1, text: "Sample Text", master_toggle: false}



답변

defaultValue는 초기로드에만 해당됩니다.

입력을 초기화하려면 defaultValue를 사용해야하지만 상태를 사용하여 값을 변경하려면 값을 사용해야합니다. 개인적으로 나는 초기화하는 경우 defaultValue를 사용하고 제출할 때 값을 얻기 위해 refs를 사용하는 것을 좋아합니다. 리 액트 문서 ( https://facebook.github.io/react/docs/forms.htmlhttps://facebook.github.io/react/docs/working-with-the-) 에 대한 참조 및 입력에 대한 자세한 정보가 있습니다. browser.html .

입력 내용을 다시 작성하는 방법은 다음과 같습니다.

awayMessageText = if this.state.awayMessage then this.state.awayMessage.text else ''
<input ref="text" onChange={this.onTextChange} placeholder="Placeholder Text" value={@state.awayMessageText} />

또한 실제로 값을 ‘자리 표시 자 텍스트’로 설정하기 때문에했던 것처럼 자리 표시 자 텍스트를 전달하고 싶지 않습니다. undefined 및 nil은 기본적으로 값을 defaultValue로 전환하기 때문에 여전히 빈 값을 입력에 전달할 필요가 있습니다. https://facebook.github.io/react/tips/controlled-input-null-value.html .

getInitialState는 API 호출을 할 수 없습니다.

getInitialState가 실행 된 후 api 호출을해야합니다. 귀하의 경우에는 componentDidMount에서 할 것입니다. https://facebook.github.io/react/tips/initial-ajax.html 예제를 따르십시오. .

또한 반응으로 구성 요소 수명주기를 읽는 것이 좋습니다. https://facebook.github.io/react/docs/component-specs.html .

수정 및로드 상태로 다시 작성

개인적으로 나는 렌더링에서 로직을 사용하고 내 상태에서 ‘로드’를 사용하고 양식이로드되기 전에 글꼴 멋진 스피너를 렌더링하는 것을 선호하는 경우 전체를 수행하고 싶지 않습니다. http://fortawesome.github.io/Font- Awesome / examples / . 내가 의미하는 바를 보여주는 재 작성이 있습니다. cjsx에 대한 진드기를 엉망으로 만들면 일반적으로 이렇게 coffeescript를 사용하기 때문입니다.

window.Pages ||= {}

Pages.AwayMessages = React.createClass

  getInitialState: ->
    { loading: true, awayMessage: {} }

  componentDidMount: ->
    App.API.fetchAwayMessage (data) =>
      @setState awayMessage:data.away_message, loading: false

  onToggleCheckbox: (event)->
    @state.awayMessage.master_toggle = event.target.checked
    @setState(awayMessage: @state.awayMessage)

  onTextChange: (event) ->
    @state.awayMessage.text = event.target.value
    @setState(awayMessage: @state.awayMessage)

  onSubmit: (e) ->
    # Not sure what this is for. I'd be careful using globals like this
    window.a = @
    @submitAwayMessage(@state.awayMessage)

  submitAwayMessage: (awayMessage)->
    console.log "I'm saving", awayMessage
    App.API.saveAwayMessage awayMessage, (data) =>
      if data.status == 'ok'
        App.modal.closeModal()
        notificationActions.notify("Away Message saved.")
        @setState awayMessage:awayMessage

  render: ->
    if this.state.loading
      `<i className="fa fa-spinner fa-spin"></i>`
    else
    `<div className="away-messages">
       <div className="header">
         <h4>Away Messages</h4>
       </div>
       <div className="content">
         <div className="input-group">
           <label for="master_toggle">On?</label>
           <input type="checkbox" onChange={this.onToggleCheckbox} checked={this.state.awayMessage.master_toggle} />
         </div>
         <div className="input-group">
           <label for="text">Text</label>
           <input ref="text" onChange={this.onTextChange} value={this.state.awayMessage.text} />
         </div>
       </div>
       <div className="footer">
         <button className="button2" onClick={this.close}>Close</button>
         <button className="button1" onClick={this.onSubmit}>Save</button>
       </div>
     </div>

그것은 그것을 덮을 것입니다. 이제 그것은 상태와 가치를 사용하는 형태에 대한 한 가지 방법입니다. value 대신 defaultValue를 사용한 다음 제출할 때 refs를 사용하여 값을 가져올 수도 있습니다. 그 경로로 가면 데이터를 가져 와서 양식에 소품으로 전달할 외부 쉘 구성 요소 (일반적으로 고차 구성 요소라고 함)를 사용하는 것이 좋습니다.

전반적으로 반응 문서를 끝까지 읽고 몇 가지 자습서를 수행하는 것이 좋습니다. 거기에는 많은 블로그가 있으며 http://www.egghead.io 에는 좋은 자습서가 있습니다. 내 사이트 http://www.openmindedinnovations.com 에도 몇 가지 항목이 있습니다 .


답변

이를 수정하는 또 다른 방법은 key입력 을 변경하는 것 입니다.

<input ref="text" key={this.state.awayMessage ? 'notLoadedYet' : 'loaded'} onChange={this.onTextChange} defaultValue={awayMessageText} />

업데이트 : 이것은 upvotes를 얻으므로 콘텐츠가로드되는 동안 disabled또는 readonlyprop을 올바르게 가져야한다고 말해야 하므로 ux 경험을 감소시키지 않습니다.

그리고 네, 그것은 해킹 일 가능성이 가장 높지만 작업을 완료합니다 .. 😉


답변

최선의 해결책은 아닐 수도 있지만, 코드의 모든 곳에서 재사용 할 수 있도록 아래와 같은 구성 요소를 만들 것입니다. 기본적으로 이미 반응했으면 좋겠습니다.

<MagicInput type="text" binding={[this, 'awayMessage.text']} />

구성 요소는 다음과 같습니다.

window.MagicInput = React.createClass

  onChange: (e) ->
    state = @props.binding[0].state
    changeByArray state, @path(), e.target.value
    @props.binding[0].setState state

  path: ->
    @props.binding[1].split('.')
  getValue: ->
    value = @props.binding[0].state
    path = @path()
    i = 0
    while i < path.length
      value = value[path[i]]
      i++
    value

  render: ->
    type = if @props.type then @props.type else 'input'
    parent_state = @props.binding[0]
    `<input
      type={type}
      onChange={this.onChange}
      value={this.getValue()}
    />`

배열에 의한 변경은 배열로 표현 된 경로로 해시에 액세스하는 함수입니다.

changeByArray = (hash, array, newValue, idx) ->
  idx = if _.isUndefined(idx) then 0 else idx
  if idx == array.length - 1
    hash[array[idx]] = newValue
  else
    changeByArray hash[array[idx]], array, newValue, ++idx 


답변

초기 값을 설정하는 가장 안정적인 방법은 render () {} 외에도 componentDidMount () {}를 사용하는 것입니다.

...
componentDidMount(){

    const {nameFirst, nameSecond, checkedStatus} = this.props;

    document.querySelector('.nameFirst').value          = nameFirst;
    document.querySelector('.nameSecond').value         = nameSecond;
    document.querySelector('.checkedStatus').checked    = checkedStatus;
    return;
}
...

요소를 파괴하고 새 요소로 교체하는 것이 쉽습니다.

<input defaultValue={this.props.name}/>

이렇게 :

if(document.querySelector("#myParentElement")){
    ReactDOM.unmountComponentAtNode(document.querySelector("#myParentElement"));
    ReactDOM.render(
        <MyComponent name={name}  />,
        document.querySelector("#myParentElement")
    );
};

이 버전의 마운트 해제 방법을 사용할 수도 있습니다.

ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(this).parentNode);


답변

매개 변수 “placeHolder”에 값을 제공하십시오. 예를 들면 :-

 <input
    type="text"
    placeHolder="Search product name."
    style={{border:'1px solid #c5c5c5', padding:font*0.005,cursor:'text'}}
    value={this.state.productSearchText}
    onChange={this.handleChangeProductSearchText}
    />


답변