3.组件通信
1.父子组件通信
前面的章节我们所说,父组件通过props将数据传递给子组件,那么当子组件需要向父组件通信时,我们又该怎么做呢?答案仍然是prop,父组件可以通过子组件的props传递给子组件一个回调函数,子组件在需要改变父组件的数据时,调用这个回调函数即可。
首先我们来看一下父组件向子组件传递信息的示例代码
//子组件 class UserList extends Component{ render(){ return( <div> {this.props.users.map(function(user){ //子组件通过props获取父组件传递过来的数据 return( <li key={user.id}> <span>{user.name}</span> </li> ); } }}
//父组件 class UserListContainer extends Component{ constructor (props){ super(props); this.state={ //父组件初始化state中的数据 users:[] } } componentDidMount(){ var that=this; fetch('/path/to/user-api').then(function(response){ response.json().then(function(data){ that.setState({users:data}) //父组件获取data数据 }); }); } render(){ return( <UserList users={this.state.users}/> //父组件将数据传递给子组件 ) } }
从上面的代码中我们可以发现,父组件获取数据之后通过state将数据发送给子组件,子组件通过props进行数据的接收。
那么子组件如何向父组件传递信息呢?我们看下面这一段代码
//子组件 class UserList extends Component{ constructor(props){ super(props); this.state={ newUser:'' //子组件中自定义了一个newUser属性用于保存准备向父组件传递的数据信息 }; this.handleChange=this.handleChange.bind(this); this.handleClick=this.handleClick.bind(this); } handleChange(e){ this.setState({newUser:e.target.value}); } handleClick(){ if(this.state.newUser&&this.state.newUser.length>0){ this.props.onAddUser(this.state.newUser); //通过this.props.onAddUser()访问父组件的方法并且向父组件传递数据信息 }} render(){ return( <div> {this.props.users.map(function(user){ return( <div> <li key={user.id}> <span>{user.name}</span> </li> <inpput onchange={this.handleChange} value={this.state.newUser}/> <button onclick={this.handleClick}>新增</button> //触发事件向父组件传递数据信息 </div> ); } }}
//父组件 class UserListContainer extends Component{ constructor (props){ super(props); this.state={ //父组件初始化state中的数据 users:[] }; this.handleAddUser=this.handleAddUser.bind(this); } componentDidMount(){ var that=this; fetch('/path/to/user-api').then(function(response){ response.json().then(function(data){ that.setState({users:data}) //父组件获取data数据 }); }); } //新增数据增加方法,用于提供子组件进行访问 handleAddUser(user){ var that=this; fetch('/path/to/save-user-api',{ //父组件获取子组件传递的数据并且将数据进行保存 method:'POST', body:JSON.stringify({'username':user}) }).then(function(response){ response.json().then(function(newUser){ that.setState((preState)=>({users:preState.users.concat([newUser])})) }); }); } render(){ return( <UserList users={this.state.users} onAddUser={this.handleAddUser /> //父组件将增加数据的方法传递给子组件供子组件进行调用 ) } }
2.兄弟组件通信
当两个组件不是父子关系但有相同的父组件时,称为兄弟组件。兄弟组件不能直接进行通信,需要通过状态提升的方式实现兄弟组件的通信,即把组件之间需要共享的数据保存到距离他们最近的共同父组件内,任意一个兄弟组件都可以通过父组件传递的回调函数来修改共享状态,父组件中共享状态的变化也会通过props向下传递给所有的兄弟组件,从而完成兄弟组件的通信。
示例:
//父组件 class UserListContainer extends Component{ constructor (props){ super(props); this.state={ users:[] currentUserId:null //新增currentUserId用于联系两个子组件 }; this.handleAddUser=this.handleAddUser.bind(this); this.handleCurrentUser=this.handleCurrentUser.bind(this); } componentDidMount(){ var that=this; fetch('/path/to/user-api').then(function(response){ response.json().then(function(data){ that.setState({users:data}) }); }); } //新增数据增加方法,用于提供子组件进行访问 handleAddUser(user){ var that=this; fetch('/path/to/save-user-api',{ method:'POST', body:JSON.stringify({'username':user}) }).then(function(response){ response.json().then(function(newUser){ that.setState((preState)=>({users:preState.users.concat([newUser])})) }); }); } //设置当前选中的用户 handleSetCurrentUser(userId){ this.setState({ currentUserId:userId }); } render(){ const filterUsers = this.state.users.filter((user)=>{user.id===this.state.currentUserId}); const currentUser = filterUsers.length>0?filterUsers[0]:null; return( <UserList users={this.state.users} currentUserId={this.state.currentUserId} onSetCurrentUser={this.handleSetCurrentUser} onAddUser={this.handleAddUser /> <UserDetail currentUser = {currentUser}/> ) } }