父组件通过属性的形式向子组件传值
子组件想要和父组件通信,调用父组件传递过来的方法
单项数据流:父组件可以向子组件传值,但是子组件一定不能直接的去改变这个值。
父组件:
import React ,{Component, Fragment} from 'react';
import TodoItem from './TodoItem';
import './style.css';
//react 响应式
//定义组件
class TodoList extends Component{
//constructor 在组件创建的第一个时刻自动被执行
//组件会接收外部传的参数,把这个参数传递给外部基类的构造函数
//前两行固定写法
constructor(props){
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.handleKeyUp = this.handleKeyUp.bind(this);
this.handleItemClick = this.handleItemClick.bind(this);
//在组件中创建了两个数据,数据一定要定义在state中
this.state = {
inputValue:'',
list:[]
}
}
handleInputChange(e){
// console.log(e.target.value);
// this.state.inputValue = e.target.value;不能直接这么改,会出错,使用固定的setState函数
this.setState({
inputValue:e.target.value
})
}
handleKeyUp(e){
// console.log(e.keyCode);
//回车的keyCode值为13且内容不为空
if(e.keyCode===13 && e.target.value!==''){
//this.state.inputValue;
//list中包含了list和input中的量
const list = [...this.state.list,this.state.inputValue];
//es6中如果键和值都是一样的,list:list 可以直接写list
this.setState({
list,
inputValue:''
})
}
}
handleItemClick(index){
//拿到当前数据,拷贝一个副本
const list = [...this.state.list];
list.splice(index,1);
this.setState({list});
}
getListItems(){
// 用map进行循环输出
// map方法必须进行return
return this.state.list.map((value,index)=>{
// 加入key会使react的性能更高,key值是唯一的
// 循环输出的每一项都要使用key,值不使用key会一直进行报警告
// 向todoitem传递内容,可以是任意值,例如conten,title
// 告诉子组件要显示什么,是value值
// 父子组件的概念
// 父组件通过属性的形式向子组件传值
return (
<TodoItem
// 组件上不能写事件的绑定,可以对子组件上进行绑定
content={value}
index ={index}
key={index}
// 父组件还可以给子组件传递方法
deleteFunction={this.handleItemClick}
/>
)
})
}
//render函数决定组件渲染内容
render(){
//在render函数中,this指向的是这个组件
//return一个内容出去,如果没有return出去,页面上是没有内容的
return(
<Fragment>
{/* 对于jsx语法,一个属性等于一个js变量或者一个js表达式,需要用{}引起来 */}
{/* <span>请输入内容:</span> */}
<label htmlFor ='myinput'>请输入内容:</label>
<input
id = 'myinput'
className = 'input'
value = {this.state.inputValue}
// handleInputChang函数的this指向的是undefined,需要使用bind将this指向变更成这个组件的指向,
// 也就是指向render()函数的指向,又由于render函数指向的是组件,也就是说handleInputChange也指向了这个组件
onChange = {this.handleInputChange}
//当按任意一个键,键弹起来的时候绑定的事件
onKeyUp = {this.handleKeyUp}
/>
<ul>
{this.getListItems()}
</ul>
</Fragment>
);
}
}
//在index引用之前要先将totolist暴露出去
//也就是把自己暴露出去,供别人使用
export default TodoList;
子组件
import React, {Component} from 'react';
class TodoItem extends Component{
constructor(props){
super(props);
this.handleItemClick = this.handleItemClick.bind(this);
}
handleItemClick(){
// 改变 父组件中的list数据
// 子组件想要和父组件通信,他要调用父组件传递过来的方法
// 对this.props.deleteFunction(this.props.index);进行简化
const {deleteFunction,index} = this.props;
deleteFunction(index);
}
render(){
// this.props接收父组件传递过来的东西
// 子组件通过this.props的属性,从父组件通过接收传递过来的值
const { content } =this.props; //等价于 const content = this.props.content;
return <li onClick={this.handleItemClick}>{content}</li>
}
}
export default TodoItem;
小例子:实现一次传值过程,把hello world显示在页面上
- 创建一个父组件Father
- 创建一个子组件Son
- 子组件接收父组件的属性名content,content的属性值为"hello world"
- 把hello world显示在页面上
实现思路建议:
第一步:首先我们要定义父组件和子组件且分清,谁是父组件,谁是子组件
第二步:需要把子组件引入到父组件所在的文件当中
第三步:引入子组件import Son from './Son';
第四步:首先我们要在引入过来的子组件上去自定义一个属性,比如content,接着就是我们要把传入自组建的值写入到content属性值
<div> <Son content='hello world' /> </div>
第五步:那么接下来,我们要做的就是,如何去接收父组件传递过来的值,这里就要用到props属性,他的作用就是接收传值。这样,就接收到父组件传递过来的值,其中,this.props.content中的props后面的content就是在父组件当中,在子组件上自定义的content属性
<div>{this.props.content}</div>
Father.js
import React,{ Component } from 'react';
import Son from './Son';
class Father extends Component{
render(){
return (
<div>
<Son
content='hello world'
/>
</div>
)
}
}
export default Father;
Son.js
import React,{ Component } from 'react';
class Son extends Component{
constructor(props){
super(props);
}
render(){
return (
<div>{this.props.content}</div>
)
}
}
export default Son;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Father from './Father';
ReactDOM.render(<Father />,document.getElementById('root'));