九、状态提升
通常,多个组件需要反映相同的变化数据。这时建议将共享状态提升到共同的父组件中。
let scaleNames = { celsius: "Celsius", fahrenheit: "Fahrenheit" } // 摄氏度与华氏度转换函数 function toCelsius(fahrenheit) { return (fahrenheit - 32) * 5 / 9 } function toFahrenheit(celsius) { return (celsius * 9 / 5) + 32 } // 最终输入输出 function tryConvert(temp, convert) { let input = parseFloat(temp) if (Number.isNaN(input)) { return "" } let output = convert(input) // 返回保留三位小说并四舍五入的转换结果 let res = Math.round(output * 1000) / 1000 return res.toString() } class TempInput extends React.Component { constructor(props) { super(props); // this.state = { // temp: "" // } this.handleChange = this.handleChange.bind(this) } handleChange(event) { // this.setState({ temp: event.target.value }) this.props.onTempChange(event.target.value) } render() { // let temp = this.state.temp; let temp = this.props.temp; let scale = this.props.scale; return ( <fieldset> <legend>enter temperature in {scaleNames[scale]}:</legend> <input value={temp} onChange={this.handleChange} /> </fieldset> ) } }
class Calculator extends React.Component { constructor(props) { super(props) // 状态提升 // 把TempInput需共享的state移到父组件,实现共享state this.state = { temp: "", scale: "" } this.handleCelsiusChange = this.handleCelsiusChange.bind(this); this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this) } handleCelsiusChange(temp) { this.setState({ temp: temp, scale: "celsius" }) } handleFahrenheitChange(temp) { this.setState({ temp: temp, scale: "fahrenheit" }) } render() { let scale = this.state.scale; let temp = this.state.temp let celsius = scale === 'celsius' ? temp : tryConvert(temp, toCelsius) let fahrenheit = scale === 'fahrenheit' ? temp : tryConvert(temp, toFahrenheit) return ( <div> <TempInput temp={celsius} scale="celsius" onTempChange={this.handleCelsiusChange} /> <TempInput temp={fahrenheit} scale="fahrenheit" onTempChange={this.handleFahrenheitChange} /> </div> ) } } ReactDOM.render(<Calculator />, document.getElementById('roo
任何可变数据应当只有一个相对应的唯一“数据源”。通常,state 都是首先添加到需要渲染数据的组件中去。然后,如果其他组件也需要这个 state,那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state。
然提升 state 方式比双向绑定方式需要编写更多的“样板”代码,但带来的好处是,排查和隔离 bug 所需的工作量将会变少。
十、组合vs继承
在react中,使用组合而非继承来实现组件间的代码重用。
1、包含关系
使用一个特殊的 children prop 来将他们的子组件传递到渲染结果中
function FancyBorder(props) { return ( <div className={'FancyBorder FancyBorder-' + props.color}> {props.children} </div> ); } // FancyBorder标签中所有内容都会被当作一个children传递给FancyBorder组件 function WelcomeDialog() { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder> ); } ReactDOM.render(<WelcomeDialog />, document.getElementById('root'))
你可以将任何东西作为props进行传递
2、特例关系
把一些组件看作是其他组件的特殊实例,比如 WelcomeDialog 可以说是 Dialog 的特殊实例 。在React中通过组合来实现。
function FancyBorder(props) { return ( <div className={'FancyBorder FancyBorder-' + props.color}> {props.children} </div> ); } // FancyBorder标签中所有内容都会被当作一个children传递给FancyBorder组件 function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.message} </p> </FancyBorder> ) } function WelcomeDialog() { return ( <Dialog title="Welcome" message="hello World" /> ) } ReactDOM.render(<WelcomeDialog />, document.getElementById('root'))
在class组件同样适合
class SignUpDialog extends React.Component { constructor(props) { super(props) this.state = { login: "" } this.handleChange = this.handleChange.bind(this) this.handleSignUp = this.handleSignUp.bind(this) } handleChange(event) { this.setState({ login: event.target.value }) } handleSignUp() { console.log(this.state.login) } render() { return ( <Dialog titile="Welcome" message="hello world"> <input value={this.state.login} onChange={this.handleChange} /> <button onClick={this.handleSignUp}>sign up</button> </Dialog> ) } } ReactDOM.render(<SignUpDialog />, document.getElementById('root'))
3、继承
在react中未发现使继承来构建组件层次期间你看。
Props 和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式。注意:组件可以接受任意 props,包括基本数据类型,React 元素以及函数。
如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们。