记住:React 中的数据流是单向的,并在组件层次结构中向下传递。
state:当一个组件 mounts的时候,state如果设置有默认值的会被使用,并且state可能时刻的被改变。一个子控件自身可以管理自己的state,但是需要注意的是,无法管理其子控件的state。所以可以认为,state是子控件自身私有的。
在react中,state可以看成管理页面状态的集合(实则一个对象而已),库里面的成员均为页面渲染变量,整个页面为一个状态机,当state发生变化时,页面会重新渲染,页面随state变化而变化。
const eventsArr = [
'handleText1Change',
'handleText2Change',
'handleText3Change'
];
const EmptyString = "";
class Dome extends React.Component {
constructor(props) {
super(props);
this.state = {
text1: EmptyString,
text2: EmptyString,
text3: EmptyString,
flag: true
};
this.setBindFunc();
};
setBindFunc() {
eventsArr.forEach(ev => {
this[ev] = this[ev].bind(this);
})
};
handleText1Change(e) {
this.setState({
text1: e.target.value
});
};
handleText2Change(e) {
this.state.text2 = e.target.value;
this.setState({});
};
handleText3Change(e) {
this.setState({
text3: e.tarege.value
}, () => {
this.state.flag = false;
})
};
render() {
return
type='text' value={this.state.text1} onChange={this.handleText1Change} />
type='text' value={this.state.text2} onChange={this.handleText2Change} />
type='text' value={this.state.text3} onChange={this.handleText3Change} />
};
};
state控制页面渲染,但是只给state赋值是不会导致页面刷新的,只有调用this.setState({})方法后才会执行render方法,最后导致页面重新渲染。
第一种写法:
this.setState({text1: e.target.value})为最常规的写法,执行完此方法之后会执行render方法,刷新state中的text1值。但是这里有个问题就是this.setState({})本身作为异步函数,赋值与渲染上会有先后问题,
在执行this.setState({text1: e.target.value})这个方法时,实际上this.state.text1的值没有改变。当走到render里面的时候this.state.text1的值才会发生改变,render内原则不可以写过多的赋值逻辑,如何解决呢产生方法二。
第二种写法:
this.state.text2 = e.target.value; 这种赋值可以直接改变this.state.text2的值,然后调用this.setState({})重新渲染页面,这种方式不会存在异步问题(只要调用this.setState({}),render函数是必然会走的,除非使用
shouldComponentUpdate来加以限制)。
第三种写法:
this.setState({},()=>{})这种赋值与第一种一样,主要侧重在回调函数上,回调函数是在执行完render后执行,回调函数内可以写逻辑,我们拿个简单的赋值举例,回调函数执行不会渲染页面,如果想渲染则在回调函数内在调用一次this.setState({}),这种回调函数我的理解是可以做一些与渲染无关的操作,如果与渲染有关为何非要写在回调内呢,多一次render,(我在实现页面的功能时,尽可能做到避免多余的render)。
props:props是一个组件的设置参数,可以在父控件中选择性设置。父组件对子控件的props进行赋值,并且props的值不可改变。一个子控件自身不能改变自己的 props。
props是组件之间传递数据的媒介。
const
eventsArr = [
'handleText1Change',
'handleText2Change',
'handleText3Change',
'handleText4Change'
];
const EmptyString = "";
class Dome extends React.Component {
constructor(props) {
super(props);
this.state = {
text1: EmptyString,
text2: EmptyString,
text3: EmptyString,
text4: EmptyString,
obj: {
value: EmptyString
},
flag: true
};
this.setBindFunc();
};
setBindFunc() {
eventsArr.forEach(ev => {
this[ev] = this[ev].bind(this);
})
};
handleText1Change(e) {
this.setState({
text1: e.target.value
});
};
handleText2Change(e) {
this.state.text2 = e.target.value;
this.setState({});
};
handleText3Change(e) {
this.setState({
text3: e.tarege.value
}, () => {
this.state.flag = false;
})
};
handleText4Change(oldValue, newValue) {
this.state.text4 = newValue;
};
render() {
return <div>
'text' value={this.state.text1} onChange={this.handleText1Change} />
'text' value={this.state.text2} onChange={this.handleText2Change} />
'text' value={this.state.text3} onChange={this.handleText3Change} />
this.state.text4}
obj={this.state.obj}
handleText4Change={this.handleText4Change}
/>
div>
};
};
const
Constants = {
Click: 'Click'
};
class DomeChildren extends React.Component() {
constructor(props) {
super(props);
this.state = {
text: this.props.text4,
obj: this.props.obj
};
};
handleText4Change(e) {
let
oldValue = this.state.text,
newValue = e.target.value;
this.state.text = newValue;
this.setState({});
this.props.handleText4Change(oldValue, newValue);
};
handleClick() {
//仅做例子用
this.props.text4 = "Dqhan";
this.props.obj.value = 10086;
}
render() {
return <div>
'text' value={this.state.text} handleText4Change={this.handleText4Change.bind(this)} />
<div onClick={this.handleClick.bind(this)}>{Constants.Click}div>
div>;
};
};
首先props是用于组件之间传递信息的,比如父组件Dome传递给子组件DomeChildren了text4,obj跟一个方法handleText4Change,这里我们达到了props作用的目的,当子组件内执行handleText4Change,改变了DemoChildren里面的text值同时渲染该组件,这里没有影响到Demo
当执行handleClick方法时,可以看到代码执行this.props.text4=”Dqhan”时react会报错,这说明props是不可以改变的,但是this.props.obj.value = 10086没有报错,很明显,因为obj是对象,这里我理解为,只要物理地址没有变,react就会认为是props没有改变,不然很多地方用到了数组就没招了。总结:props中简单类型不能改变,引用类型内部的属性可以改变。
supert是继承constructor的参数,但是为什么在react里面,有一些组件使用了super(props),而有一些没有写,还有在es6里就只是写了supert(),这些区别在哪呢?以及这里的这个constructor(props)…super(props)是起到什么作用呢?
调用super的原因:在ES6中,在子类的constructor中必须先调用super才能引用this
super(props)的目的:在constructor中可以使用this.props
最后,可以看下React文档,里面有一段
Class components should always call the base constructor with props.
根本原因是constructor会覆盖父类的constructor,导致你父类构造函数没执行,所以手动执行下。
直接在constructor内部 用this.props 会报错:
constructor() {
super()
console.log(this.props)//undefined
console.log(props)//error
}
constructor(props) {
super()
console.log(this.props)//undefined
console.log(props)//{}
}
constructor(props) {
super(props)
console.log(this.props)//{}
console.log(props)//{}
}
1.state 本组件内的数据 ,相对封闭的单元/结构的数据 状态
2.props 组件直接的数据流动,单向的 ,从owner向子组件
总结的来说,props是一个父组件传递给子组件的数据流,可以一直的被传递到子孙组件中。然而 state代表的是子组件自身的内部状态。从语义上讲,改变组件的状态,可能会导致dom结构的改变或者重新渲染。而props是父组件传递的参数,所以可以被用于初始化渲染和改变组件自身的状态,虽然大多数时候组件的状态是又外部事件触发改变的。
构建一个用于呈现数据模型的静态版本的应用程序,通过props来传递数据,props是一种从父级向子级传递数据的方法。在创建静态版本的时候不要使用state,state只在交互的时候使用,即随时间变化的数据。需要能够触发对底层数据模型的更改,React使用state。通过调用ReactDOM.render(),UI会更新。
使用 react 经常会遇到几个组件需要共用状态数据的情况。这种情况下,我们最好将这部分共享的状态提升至他们最近的父组件当中进行管理。这时候就需要state与props结合进行使用。我们写一个名为 Calculator 的组件。它会渲染一个 来接受用户输入,然后将输入的温度值保存在 this.state.temperature 当中。之后呢,它会根据输入的值渲染出 BoilingVerdict 组件。在BoilingVerdict 组件组件中可以通过this.props.temperature进行数据的获取,进而完成了多组件的通信
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
return (
);
}
}