2015-05-30 18 views
1

以下小提琴使用React 0.13將3個輸入範圍顯示爲受控組件。狀態更改後,彩色方塊更新以顯示新的RGB顏色。 http://jsfiddle.net/faria/yw6q3s9L/反應:輸入範圍滑塊不會在Chrome中向其所有者傳播上一個值

它的工作原理與我在火狐瀏覽器中的期望/願望一樣,但不適用於Chrome。具體來說,彩色正方形組件顯示倒數第二個值,而滑塊顯示最近的值。

這是React/Chrome錯誤嗎?或者我可以在我的代碼中修復某些內容?

代碼:

var ColorDisplay = React.createClass({ 
    propTypes: { 
     red: React.PropTypes.number.isRequired, 
     green: React.PropTypes.number.isRequired, 
     blue: React.PropTypes.number.isRequired 
    }, 
    _toHex: function(s) { 
     var hex = parseInt(s,10).toString(16); 
     return hex.length == 1 ? "0" + hex : hex; 
    }, 
    render: function() { 
     var rr = this._toHex(this.props.red), 
      gg = this._toHex(this.props.green), 
      bb = this._toHex(this.props.blue); 
     var color = "#" + rr + gg + bb; 
     var divStyle = {backgroundColor: color}; 
     return (
      <div id="display"> 
       <h3>{color}</h3> 
       <div id="color-swatch" style={divStyle}></div> 
      </div> 
     ); 
    } 
}); 

var ColorSlider = React.createClass({ 
    propTypes: { 
     red: React.PropTypes.number.isRequired, 
     green: React.PropTypes.number.isRequired, 
     blue: React.PropTypes.number.isRequired, 
     changeHandler: React.PropTypes.func.isRequired 
    }, 
    getInitialState: function() { 
     return { 
      red: this.props.red, 
      green: this.props.green, 
      blue: this.props.blue 
      }; 
    }, 
    handleOnChange: function(name, event) { 
     var new_state = {}; 
     new_state[name] = event.target.value; 
     this.setState(new_state); 
     this.props.changeHandler(); 
    }, 
    handleClick: function(name, event) { 
     var new_state = {}; 
     var self = this; 
     ['red','green','blue'].forEach(function(name) { 
      new_state[name] = React.findDOMNode(self.refs[name]).value; 
     }); 
     this.setState(new_state); 
     this.props.changeHandler(); 
    }, 
    _getRGB: function() { 
     return this.state; 
    }, 
    _toHex: function(s) { 
     var hex = parseInt(s,10).toString(16); 
     return hex.length == 1 ? "0" + hex : hex; 
    }, 
    render: function() { 
     var red_style = {color: 'red'}; 
     var grn_style = {color: 'green'}; 
     var blue_style = {color: 'blue'}; 
     var min=0; 
     var max=255; 
     var step=1; 
     var rr = this._toHex(this.state.red), 
      gg = this._toHex(this.state.green), 
      bb = this._toHex(this.state.blue); 
     return (
      <div id="slider"> 
       <div> 
        <label htmlFor="id_red">Red</label> 
        <input 
         name="red" 
         type="range" 
         min={min} 
         max={max} 
         step={step} 
         value={this.state.red} 
         onInput={this.handleOnChange.bind(this, "red")} 
         onChange={this.handleOnChange.bind(this, "red")} 
         ref="red" 
         id="id_red" 
         /> 
        <span style={red_style}>{this.state.red}/{rr}</span> 
       </div> 
       <div> 
        <label htmlFor="id_green">Green</label> 
        <input 
         name="green" 
         type="range" 
         min={min} 
         max={max} 
         step={step} 
         value={this.state.green} 
         onInput={this.handleOnChange.bind(this, "green")} 
         onChange={this.handleOnChange.bind(this, "green")} 
         ref="green" 
         id="id_green" 
         /> 
        <span style={grn_style}>{this.state.green}/{gg}</span> 
       </div> 
       <div> 
        <label htmlFor="id_blue">Blue</label> 
        <input 
         name="blue" 
         type="range" 
         min={min} 
         max={max} 
         step={step} 
         value={this.state.blue} 
         onInput={this.handleOnChange.bind(this, "blue")} 
         onChange={this.handleOnChange.bind(this, "blue")} 
         ref="blue" 
         id="id_blue" 
         /> 
        <span style={blue_style}>{this.state.blue}/{bb}</span> 
       </div> 
       <button onClick={this.handleClick}>Set Color (hack to sync slider with square on Chrome)</button> 
      </div> 
     ); 
    } 
}); 

var App = React.createClass({ 
    getInitialState: function() { 
     return { red: 0, green: 0, blue: 0 }; 
    }, 
    update: function() { 
     var rgb = this.refs.slider._getRGB(); 
     // the values are now strings! 
     this.setState({ 
      red: rgb.red, 
      green: rgb.green, 
      blue: rgb.blue 
     }); 
    }, 
    render: function() { 
     return(
      <div id="color-app"> 
       <ColorDisplay ref="color" 
        red={this.state.red} 
        green={this.state.green} 
        blue={this.state.blue} 
       /> 
       <ColorSlider ref="slider" 
        red={this.state.red} 
        green={this.state.green} 
        blue={this.state.blue} 
        changeHandler={this.update} 
       /> 
      </div> 
     ); 
    } 
}); 
React.render(<App />, document.getElementById('app')); 

回答

1

你必須在你的ColorSlider一個handleOnChange競爭狀態。在調用setState之後,一旦狀態被更新,您應該調用this.props.changeHandler()。這是因爲setState不是同步的。然而,它可能正確運行在Firefox上的原因是因爲它可能是一場非常快速的比賽,而且Firefox恰好出現在沒有顯示錯誤的一側。

,迫使它總是ColorSlider工作,消除種族,使用這樣的handleOnChange

handleOnChange: function(name, event) { 
    var new_state = {}; 
    new_state[name] = event.target.value; 
    this.setState(new_state, function() { 
     this.props.changeHandler(); 
    }); 
} 

,它會工作得很好。這樣做確保this.props.changeHandler僅在狀態實際更新並呈現後才被調用。這是因爲這個具體原因,setState有一個可選的回調。

請注意,您不必將setState中的回調綁定到this,因爲React會自動爲您綁定它。

進一步編輯:

你也只能得到發生在所有的,因爲你直接從父(壞)調用子組件的功能這個問題,你直接從DOM時讀取數據你不需要。從外部調用組件的方法在React中是一個巨大的禁忌。你應該做的是通過onChange回調函數將新的顏色值傳遞給鏈上,並在父代中以這種方式作出反應。

EG:

handleOnChange: function(name, event) { 
    var new_state = {}; 
    new_state[name] = event.target.value; 
    this.setState(new_state, function() { 
    this.props.changeHandler(name, this.state[name]); 
    }) 
} 

讓您通過更改update功能類似設置在父App組件的顏色變化:

update: function(name, value) { 
    var stateChange = {}; 
    stateChange[name] = value; 
    this.setState(stateChange); 
} 
+0

「的setState不同步」和「通鏈條上的新價值「......這對我來說是一個重要的教訓,謝謝。 – FariaC