React从入门到精通系列之(10)提升state
十、提升state通常,如果有几个组件需要反映相同的变化数据。 我们建议将共享state提升到层级最近的,并且是共同的父组件上。 让我们看看这是如何工作的。 在本节中,我们将创建一个温度计算器来计算水是否在给定温度下沸腾。 我们将从一个名为 function BoilingVerdict(props) { if (props.celsius >= 100) { return <p>水沸腾了</p> } return <p>水没有沸腾</p> } 接下来,我们创建一个名字叫 此外,它还会根据当前输入值渲染 import React from 'react'; import ReactDOM from 'react-dom'; function BoilingVerdict(props) { if (props.celsius >= 100) { return <p>水沸腾了</p> } return <p>水没有沸腾</p> } class Calculator extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.change = this.change.bind(this); } change(e) { this.setState({value: e.target.value}); } render() { const value = this.state.value; return ( <fieldset> <legend>请输入温度</legend> <input value={value} onChange={this.change}/> <BoilingVerdict celsius={parseFloat(value)}/> </fieldset> ); } } ReactDOM.render( <Calculator />,document.getElementById('root') ); 添加第二个input我们的新需求是,除了输入 我们可以从 const scaleNames = { c: 'Celsius',f: 'Fahrenheit' } class TemperatureInput extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.change = this.change.bind(this) } change(e) { this.setState({value: e.target.value}); } render() { const value = this.state.value; const scale = this.props.scale; return ( <fieldset> <legend>输入{scaleName[scale]}温度</legend> <input value={value} onChange={this.change} /> </fieldset> ); } } 我们现在可以更改计算器来渲染两个单独的温度输入: class Calculator extends React.Component { constructor(props) { super(props); } render() { return ( <div> <TemperatureInput scale='f' /> <TemperatureInput scale='c' /> </div> ); } } ReactDOM.render( <Calculator />,document.getElementById('root') ) 我们现在有两个输入框,但是当您在其中一个输入温度时,另一个不更新。 这违反了我们的要求:我们希望保持它们同步。 我们也不能从 提升state首先,我们将写两个函数来将摄氏度转换为华氏度,然后返回: // 将华氏度转换为摄氏度 function toCelsius(f) { return (f - 32) * 5 / 9; } // 将摄氏度转换为华氏度 function toFahrenheit(c) { return (c * 9 / 5) + 32; } 这两个函数转换数字。 我们将写另一个函数,它接受一个字符串值和一个转换函数作为参数,并返回一个字符串。 我们将使用它来计算一个输入基于另一个输入的值。 如果传入一个无效的 function tryConvert(value,convert) { const input = parseFloat(value); if (Number.isNaN(input)) { return ''; } const output = convert(input); const rounded = Math.round(output * 1000) / 1000; return String(rounded); } 例如, class Temperature extends React.Component { constructor(props) { super(props); this.change = this.change.bind(this); } change(e) { this.props.onChange(e.target.value); } render() { const value = this.props.value; const scale = this.props.scale; return ( <fieldset> <legend>请输入{scaleName[scale]}温度</legend> <input value={value} onChange={this.change} /> </fieldset> ); } } 如果几个组件需要访问相同的state,这是一个state应该提升到层级最近的共同父级组件的标志。 在我们的例子中,这是那个 我们可以存储两个输入框的值,但事实证明这是没有必要的。 它足以存储最近更改的输入的 输入保持同步,因为它们的值是从相同的 class Calculator extends React.Component { constructor(props) { super(props); this.state = {value: '',scale: 'c'}; this.CelsiusChange = this.CelsiusChange.bind(this); this.FahrenheitChange = this.FahrenheitChange.bind(this); } CelsiusChange() { this.setState({scale: 'c',value}); } FahrenheitChange() { this.setState({scale: 'f',value}); } render() { const scale = this.state.scale; const value = this.state.value; const celsius = scale === 'f' ? tryConvert(value,toCelsius) : value; const fahrenheit = scale === 'c' ? tryConvert(value,toFahrenheit) : value; return ( <div> <Temperature scale="c" value={celsius} onChange={this.CelsiusChange} /> <Temperature scale="f" value={fahrenheit} onChange={this.FahrenheitChange} /> <BoilingVerdict celsius={parseFloat(celsius)} /> </div> ); } } 最终代码: import React from 'react'; import ReactDOM from 'react-dom'; const scaleNames = { c: 'Celsius',f: 'Fahrenheit' }; function BoilingVerdict(props) { if (props.celsius >= 100) { return <p>水沸腾了</p> } return <p>水没有沸腾</p> } function toCelsius(f) { return (f - 32) * 5 / 9; } function toFahrenheit(c) { return (c * 9 / 5) + 32; } function tryConvert(value,convert) { const input = parseFloat(value); if (Number.isNaN(input)) { return ''; } const output = convert(input); const rounded = Math.round(output * 1000) / 1000; return String(rounded); } class TemperatureInput extends React.Component { constructor(props) { super(props); this.change = this.change.bind(this); } change(e) { this.props.onChange(e.target.value); } render() { const value = this.props.value; const scale = this.props.scale; return ( <fieldset> <legend>请输入{scaleNames[scale]}温度</legend> <input value={value} onChange={this.change}/> </fieldset> ); } } class Calculator extends React.Component { constructor(props) { super(props); this.state = {value: '',scale: 'c'}; this.CelsiusChange = this.CelsiusChange.bind(this); this.FahrenheitChange = this.FahrenheitChange.bind(this); } CelsiusChange(value) { this.setState({scale: 'c',value}); } FahrenheitChange(value) { this.setState({scale: 'f',toFahrenheit) : value; return ( <div> <TemperatureInput scale="c" value={celsius} onChange={this.CelsiusChange}/> <TemperatureInput scale="f" value={fahrenheit} onChange={this.FahrenheitChange}/> <BoilingVerdict celsius={parseFloat(celsius)}/> </div> ); } } ReactDOM.render( <Calculator />,document.getElementById('root') ); 现在,无论您编辑哪个输入框, 经验教训对于在React应用程序中更改的任何数据,都应该有一个唯一的 提升state会涉及编写比双向绑定方法更多的“样板”代码。但这样做有一个好处,就是开发者可以很快就找到错误。由于所有的state都 如果某些东西可以从prps或state派生,它都不应该再继续呆在state里。 当您在UI中看到错误时,可以使用 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |