一、组件内部的state
1.什么是state?
state叫做状态,是每一个类组件都有的属性。函数式组件,没有state。
在任何类组件的构造函数里面,可以用this.state = {}来给类的实例添加state属性。
在render里面,可以用{this.state.a}这样的插值来显示出每一个属性的值。
import React from "react";
import ReactDOM from "react-dom";
export default class App extends React.Component {
constructor() {
super();
this.state = {
a : 100
}
}
render() {
return <div>
<h1>{this.state.a}</h1>
</div>
}
}
2.setState()
组件的this.setState()函数可以用来更改state的值,当state变化的时候,组件视图会自动更新。
import React from "react";
import ReactDOM from "react-dom";
export default class App extends React.Component {
constructor() {
super();
this.state = {
a : 100
}
}
render() {
return <div>
<button onClick={()=>{
this.setState({
a : this.state.a + 1
})
}}>按我</button>
<h1>{this.state.a}</h1>
</div>
}
}
- 我们react中的事件监听,要写在标签上(虽然之前说,前端3层要求分离,要求html、js、css尽量分离,但是react又将事件监听写在了标签上)。
- 事件名onClick而不是onclick,注意大写字母C。因为react将每一个事件名都进行了拓展,所以onClick是react自己的方法。同理,所有事件名的on后面的首字母都是大写:onMouseEnter、onDoubleClick、onKeyDown。
- onClick=后面紧跟{},表示插值。大括号里面,是一个箭头函数。注意这个函数必须是箭头函数,否则this错误。
<button onClick={()=>{}}></button>
- setState是定义在React.Component类中的方法,所以我们的任何一个组件都能调用this.setState()。表示“设置state”。语法是
this.setState({ 要设置的k : 新的v });
- setState不仅仅能够改变实例的state的属性值,而且能够产生视图刷新。而如果不用setState(),只是让state的属性值进行改变,此时视图是不刷新的。
3.提炼出事件处理函数
我们之前的onClick后面直接跟上了{()=>{}}。实际上可以提炼出来。
写法1:
import React from "react";
import ReactDOM from "react-dom";
export default class App extends React.Component {
constructor() {
super();
this.state = {
a : 100
}
}
//单击事件的处理函数
clickHandler(){
this.setState({
a : this.state.a + 1
});
}
render() {
return <div>
<button onClick={this.clickHandler.bind(this)}>按我</button>
<h1>{this.state.a}</h1>
</div>
}
}
- 提炼成为组件的方法(实际上写在了构造器的prototype上,实例的原型上),在onClick调用的时候,必须写bind(this),将调用的这个函数的上下文绑定为组件的实例。可以当做是一个固定的语法!
写法2(若想要传参)
如何传参数?
import React from "react";
import ReactDOM from "react-dom";
export default class App extends React.Component {
constructor() {
super();
this.state = {
a : 100
}
}
//单击事件的处理函数
clickHandler(n){
this.setState({
a : this.state.a + n
});
}
render() {
return <div>
<button onClick={()=>{this.clickHandler(1)}}>按我</button>
<button onClick={()=>{this.clickHandler(2)}}>按我</button>
<button onClick={()=>{this.clickHandler(3)}}>按我</button>
<button onClick={()=>{this.clickHandler(4)}}>按我</button>
<h1>{this.state.a}</h1>
<div style=<!--0-->></div>
</div>
}
}
三、表单受控
- 我们现在给组件设置一个state,希望文本框和这个state实时相等。
- 我们说,这个文本框和state进行了双向数据绑定,react中称为这个文本框“受控”了。
- 就是说当state改变的时候文本框的内容改变,而表单内容改变数据也会改变,实现了双向绑定。
value onChange形式的表单受控
此时就要记住 value onChange (一说到受控就该想到)
import React from "react";
import ReactDOM from "react-dom";
export default class App extends React.Component {
constructor() {
super();
this.state = {
a : "我爱你"
}
}
render() {
return <div>
<h1>{this.state.a}</h1>
<input type="text" value={this.state.a} onChange={(e)=>{
this.setState({
a : e.target.value
})
}}/>
</div>
}
}
- 单行文本、多行文本、range条、select下拉菜单的受控是value onChange
其他表单受控
1.单选按钮radio
<p>
<label><input type="radio" name="sex" checked={this.state.sex == "男"} onChange={(e)=>{
this.setState({sex : "男"})
}}/>男</label>
<label><input type="radio" name="sex" checked={this.state.sex == "女"} onChange={(e) => {
this.setState({ sex: "女" })
}}/>女</label>
<label><input type="radio" name="sex" checked={this.state.sex == "保密"} onChange={(e) => {
this.setState({ sex: "保密" })
}}/>保密</label>
</p>
2.复选框checkbox
<p>
<label>
<input type="checkbox" checked={this.state.tongyixieyi} onChange={(e)=>{
this.setState({tongyixieyi : e.target.checked})
}}/> 我已阅读上面的协议
</label>
</p>
如果复选框是一组,比如让你选择自己的爱好,此时就要和一个数组值进行受控双向绑定:
套路就是checked里面用includes判断是否在数组中,onChange来判断区别是加项还是减项。
//增加爱好
addHobby(item){
this.setState({
hobby : [...this.state.hobby , item]
});
}
//删除某一个爱好
delHobby(item) {
this.setState({
hobby: this.state.hobby.filter(_item => _item != item)
});
}
<p>
<label>
<input type="checkbox" checked={this.state.hobby.includes("篮球")} onChange={(e)=>{
if(e.target.checked){
this.addHobby("篮球");
}else{
this.delHobby("篮球");
}
}}/>篮球
</label>
<label>
<input type="checkbox" checked={this.state.hobby.includes("足球")} onChange={(e) => {
if (e.target.checked) {
this.addHobby("足球");
} else {
this.delHobby("足球");
}
}}/>足球
</label>
<label>
<input type="checkbox" checked={this.state.hobby.includes("羽毛球")} onChange={(e) => {
if (e.target.checked) {
this.addHobby("羽毛球");
} else {
this.delHobby("羽毛球");
}
}}/>羽毛球
</label>
</p>
四、非受控组件ref标记
我们现在遇见一个input框,就喜欢和state进行双向数据绑定,简称受控。实际上,也可以不受控。
不受控的表单元素,往往都要加上ref标记,然后用this.refs.***来得到它。
import React from "react";
import ReactDOM from "react-dom";
import classnames from "classnames";
export default class App extends React.Component {
constructor() {
super();
}
render() {
return <div>
<p>
<input type="text" ref="kuang"/>
</p>
<p>
<button onClick={()=>{
alert(this.refs.kuang.value)
}}>按我</button>
</p>
</div>
}
}
- ref就是id,一个组件中,不能有相同名字的ref。但是this.refs.**一定选择的是本组件的东西,不会选择其他组件的东西。
五、组件之间的数据传递
目录结构如下:
目录结构如下:
test
|-node_modules
|-www
|-app
|-main.js
|-App.js
|-Child.js
|-index.html
|-webpack.config.js
|-package.json
父子关系:
main.js(父)中引入App.js(子); App.js(父)中引入Child.js(子)
认识props
- 在父组件中,通过在子组件的标签上罗列k=v形式的参数,以达到给子组件传值的目的。
- 在子组件中用{this.props.**}的形式,接收父亲传入的参数。
- props是properties属性的简写。
props是只读的,子组件不能修改props
下面的代码是错误的:
return <div>
<h1>我是子组件,我收到了父亲的参数:{this.props.a}</h1>
<button onClick={()=>{
this.props.a ++;
}}>按我</button>
</div>
子组件若想修改父亲的值怎么办
方法:父亲一并传入函数,儿子调用父亲的函数,改变父亲的值
父组件App.js:
除了传给儿子a值以外,还传了设置a值的函数给儿子。
import React from "react";
import ReactDOM from "react-dom";
import classnames from "classnames";
import Child from "./Child.js";
export default class App extends React.Component {
constructor() {
super();
this.state = {
a : 10
}
}
setA(a){
this.setState({a});
}
render() {
return <div>
<h1>我是父组件{this.state.a}</h1>
<Child a={this.state.a} setA={this.setA.bind(this)}></Child>
</div>
}
}
子组件Child.js
如果要改变父亲的值,就要调用父亲传给自己的函数。
import React from "react";
import ReactDOM from "react-dom";
import classnames from "classnames";
export default class Child extends React.Component {
constructor() {
super();
}
render() {
return <div>
<h1>我是子组件,我收到了父亲的参数:{this.props.a}</h1>
<button onClick={()=>{
this.props.setA(this.props.a + 1);
}}>按我</button>
</div>
}
}
所以本质上,改变父亲的值,依然是父亲自己的函数在实现。
只对父亲负责!不对兄弟负责!
react编程必须养成的思维:组件只有父子之间有关系,兄弟和兄弟之间没有任何关系!兄弟和兄弟之间不需要考虑彼此对彼此造成的任何的影响,只需要考虑对父亲的影响即可。