状态提升究竟是什么东西呢?别急,下面让我们一步一步来看看究竟要怎么使用状态提升
假设我们有这样一个需求,提供两个输入框(分别属于两个组件),保证输入框里面的内容同步
好,下面我们先来封装一个输入框组件 Input
class Input extends React.Component { constructor(props) { super(props) // 输入框里的内容保存在组件的 state 当中 this.state = { content: '' } this.handleChange = this.handleChange.bind(this) } handleChange(e) { this.setState({ content: e.target.value }) } render() { return ( <input type='text' value={ this.state.content } onChange={ this.handleChange } /> ) } }
然后我们另外定义一个组件 AllInput
,在这个组件中包含两个 Input
组件,这样我们就得到两个输入框
class AllInput extends React.Component { constructor(props) { super(props) } render() { // 这里包含两个 `Input` 组件 return ( <div> <Input /> <br /><br /> <Input /> </div> ) } }
好,下一个要解决的问题是怎么使两个输入框的内容同步
在两个 Input
组件中,它们各自的内容保存在各自的 state 当中,要怎么做才能使两个组件共享数据呢?
答案是 状态提升,即将两个组件需要共享的数据保存在共同的父组件中,然后子组件通过 props 获取父组件数据
也就是说,我们可以将两个子组件 Input
的数据保存在它们的父组件 AllInput
当中
我们先来看看怎么修改父组件的定义:
class AllInput extends React.Component { constructor(props) { super(props) // 在父组件中添加 state 对象,用于保存数据 this.state = { content: '' } this.handleContentChange = this.handleContentChange.bind(this) } // 定义修改 state 的方法,通过 props 传递给子组件使用 // 接收一个参数(新的数据) handleContentChange(newContent) { this.setState({ content: newContent }) } render() { // 通过 props 将 state 和修改 state 的方法都传递给子组件 return ( <div> <Input content={ this.state.content } onContentChange={ this.handleContentChange }/> <br /><br /> <Input content={ this.state.content } onContentChange={ this.handleContentChange }/> </div> ) } }
然后我们再来修改子组件定义:
class Input extends React.Component { constructor(props) { super(props) // 数据可以不再保存在子组件的 state 当中 this.handleChange = this.handleChange.bind(this) } handleChange(e) { // 通过 props 获取父组件的 setState(修改数据的方法) // 传入一个参数(新的数据) this.props.onContentChange(e.target.value) } render() { // 通过 props 获取父组件的 state(数据) return ( <input type='text' value={ this.props.content } onChange={ this.handleChange } /> ) } }
通过状态提升,这样就可以实现组件之间的数据共享啦,一份完整的可运行的代码如下:
<!DOCTYPE html> <html> <head> <title>Demo</title> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone"></script> </head> <body> <div id="app"></div> <script type="text/babel"> class Input extends React.Component { constructor(props) { super(props) this.handleChange = this.handleChange.bind(this) } handleChange(e) { this.props.onContentChange(e.target.value) } render() { return ( <input type='text' value={ this.props.content } onChange={ this.handleChange } /> ) } } class AllInput extends React.Component { constructor(props) { super(props) this.state = { content: '' } this.handleContentChange = this.handleContentChange.bind(this) } handleContentChange(newContent) { this.setState({ content: newContent }) } render() { return ( <div> <Input content={ this.state.content } onContentChange={ this.handleContentChange }/> <br /><br /> <Input content={ this.state.content } onContentChange={ this.handleContentChange }/> </div> ) } } ReactDOM.render( <AllInput />, document.getElementById('app') ) </script> </body> </html>