09. 状态提升 (共享状态)
通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。
在 React 中,将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的“状态提升”
两个输入框共享数据的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
| const scaleNames = { c: '摄氏度', f: '华氏度' };
function toCelsius(fahrenheit) { return (fahrenheit - 32) * 5 / 9; }
function toFahrenheit(celsius) { return (celsius * 9 / 5) + 32; }
function tryConvert(temperature, convert) { const input = parseFloat(temperature); if (Number.isNaN(input)) { return ''; } const output = convert(input); const rounded = Math.round(output * 1000) / 1000; return rounded.toString(); }
function BoilingVerdict(props) { if (props.celsius >= 100) { return <p>水会沸腾.</p>; } return <p>水不会沸腾.</p>; }
class TemperatureInput extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange(e) { this.props.onTemperatureChange(e.target.value); }
render() { const temperature = this.props.temperature; const scale = this.props.scale; return ( <fieldset> <legend>输入温度-{scaleNames[scale]}:</legend> <input value={temperature} onChange={this.handleChange} /> </fieldset> ); } }
class Calculator extends React.Component { constructor(props) { super(props); this.handleCelsiusChange = this.handleCelsiusChange.bind(this); this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this); this.state = {temperature: '', scale: 'c'}; } handleCelsiusChange(temperature) { this.setState({scale: 'c', temperature}); } handleFahrenheitChange(temperature) { this.setState({scale: 'f', temperature}); } render() { const scale = this.state.scale; const temperature = this.state.temperature; const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature; const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature; return ( <div> <TemperatureInput scale="c" temperature={celsius} onTemperatureChange={this.handleCelsiusChange} /> <TemperatureInput scale="f" temperature={fahrenheit} onTemperatureChange={this.handleFahrenheitChange} /> <BoilingVerdict celsius={parseFloat(celsius)} /> </div> ); } }
ReactDOM.render( <Calculator />, document.getElementById('root') );
|
在 CodePen 上尝试
::: note
- 父组件给所有子组件传入state的值
- 子组件修改值时调用父组件的方法并把值传出
- 父组件接收到值之后修改state
- state被修改之后重新执行render函数,并回到第1步
:::
小结
React开发者工具(debug)
当你在 UI 中发现错误时,可以使用 React 开发者工具 来检查问题组件的 props,并且按照组件树结构逐级向上搜寻,直到定位到负责更新 state 的那个组件。