React State && 事件处理 Event&& 组件通信
React 基础知识
State
State 状态
import React, { Component } from "react";
export default class StateCopm extends Component {
/*
* 记住了:
* state只能在当前组件中定义,也只能在当前组件中修改
* 实例属性定义形式
! 构造函数定义形式 - 推荐
*/
constructor(props) {
super(props);
this.state = {
info: "李大傻蛋"
};
}
// state = {
// name:'lishanyu'
// }
changeState = props => {
/*
! 1. 事件处理程序我们是直接定义为实例方法
! 2. 事件处理程序我们建议写成箭头函数 - this指向不改变
*/ // * 点击按钮改变状态
/*
! 1. 事件处理程序我们是直接定义为实例方法
! 2. 事件处理程序我们建议写成箭头函数 - this指向不改变
*/
/*
? 修改状态
! 在React中状态的修改只能使用setState()
! setState() 的作用是用来改变状态 更新视图的
! setState是异步的
* setState( obj | function , [ callback ] ) 参数是有两个的
*/
// this.setState({
// info:"的确是是傻蛋!!!"
// })
this.setState(
() => {
console.log(1);
return {
info: "第一个参数是函数"
};
},
() => {
console.log("张浩雨: StateCopm", 2);
// console.log("这里是第二个参数(函数))");
document.querySelector(".div").style.background = "pink";
}
);
console.log(3);
//! 打印结果为 3 1 2
};
render() {
return (
<div>
<button onClick={this.changeState}>++++</button>
{/* <p>state 的状态 { this.state.name }</p> */}
<p>state 的状态--constructor {this.state.info}</p>
<div className="div">
<h5>XSS的原理和分类</h5>
</div>
</div>
);
}
}
state 渲染
import React, { Component } from "react";
export default class ListComp extends Component {
constructor(props) {
super(props);
this.state = {
lists: [
{
id: 1,
shop_name: "汽车?"
},
{
id: 2,
shop_name: "衣服?"
},
{
id: 3,
shop_name: "零食?"
}
]
};
}
// renderItem = () => {
// const { lists } = this.state;
// return (
// lists.map((elm,i)=> {
// return <li key= { elm.id }>{elm.shop_name}</li>
// })
// )
// }
renderItem = () => {
const { lists } = this.state;
return lists.map(elm => <li key={elm.id}>{elm.shop_name}</li>);
};
render() {
return (
<div>
<ul>{this.renderItem()}</ul>
</div>
);
}
}
state 添加案例
import React, { Component } from "react";
export default class StateDemo extends Component {
constructor(props) {
super(props);
this.state = {
arr: [11, 22, 33, 44, 55]
};
}
addItem = () => {
this.setState(() => {
this.state.arr.push(66);
return {
arr: this.state.arr
};
});
};
render() {
const { arr } = this.state;
return (
<div>
<h2>渲染数组</h2>
<button onClick={this.addItem}> ➕</button>
<ul>
{arr.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
}
事件处理 Event
如何绑定事件
采用 on+事件名的方式来绑定一个事件,注意,这里和原生的事件是有区别的,原生的事件全是小写onclick
, React 里的事件是驼峰onClick
,React 的事件并不是原生事件,而是合成事件。
事件 handler 的写法 【 王牌 || 王者】
- 直接在 render 里写行内的箭头函数(不推荐)
import React, { Component } from "react";
export default class Event1 extends Component {
render() {
return (
<div>
<button
onClick={() => {
alert("张浩雨");
}}
>
render中直接写箭头函数{" "}
</button>
</div>
);
}
}
- 在组件内使用箭头函数定义一个方法(推荐)
import React, { Component } from "react";
export default class Event2 extends Component {
constructor(props) {
super(props);
this.state = {
money: 2000
};
}
changeMoney = () => {
this.setState({
money: 9999
});
};
render() {
const { money } = this.state;
return (
<div>
<button onClick={this.changeMoney}>
在组件内使用箭头函数定义一个方法(推荐)
</button>
<p>{money}</p>
</div>
);
}
}
- 直接在组件内定义一个非箭头函数的方法,然后在 render 里直接使用
onClick={this.handleClick.bind(this)}
(不推荐)
import React, { Component } from "react";
export default class Event3 extends Component {
constructor(props) {
super(props);
this.state = {
money: 2000
};
}
changeMoney() {
this.setState({
money: 8888
});
}
render() {
const { money } = this.state;
return (
<div>
<button onClick={this.changeMoney.bind(this)}>
直接在组件内定义一个非箭头函数的方法
</button>
<p>{money}</p>
</div>
);
}
}
- 直接在组件内定义一个非箭头函数的方法,然后在 constructor 里 bind(this)(推荐)
import React, { Component } from "react";
export default class Event4 extends Component {
constructor(props) {
super(props);
this.state = {
money: 2000
};
this.changeMoney = this.changeMoney.bind(this);
}
changeMoney() {
this.setState({
money: 7777
});
}
render() {
const { money } = this.state;
return (
<div>
<button onClick={this.changeMoney}>
直接在组件内定义一个非箭头函数的方法,然后在constructor里bind(this)(推荐)
</button>
<p>{money}</p>
</div>
);
}
}
注意: 事件不能定义在函数式组件中
Event 对象
和普通浏览器一样,事件 handler 会被自动传入一个
event
对象,这个对象和普通的浏览器event
对象所包含的方法和属性都基本一致。不同的是 React 中的event
对象并不是浏览器提供的,而是它自己内部所构建的。它同样具有event.stopPropagation
、event.preventDefault
这种常用的方法
import React, { Component } from "react";
export default class EventObj extends Component {
enentHandle = ev => {
console.log("张浩雨: EventObj -> ev", ev);
console.log("张浩雨: EventObj -> ev.target", ev.target);
};
render() {
return (
<div>
<button onClick={this.enentHandle}>Event 对象</button>
</div>
);
}
}
事件对象中的值很多都是 null,但是可以正常使用
事件的参数传递
- 在
render
里调用方法的地方外面包一层箭头函数
import React, { Component } from "react";
export default class EventArgu1 extends Component {
constructor(props) {
super(props);
this.state = {
money: 0
};
}
changeMoney = val => {
this.setState({
money: val
});
};
render() {
const { money } = this.state;
return (
<div>
<button
onClick={() => {
this.changeMoney(1000);
}}
>
**在`render`里调用方法的地方外面包一层箭头函数**{" "}
</button>
<p>money:{money}</p>
</div>
);
}
}
- 在
render
里通过this.handleEvent.bind(this, 参数)
这样的方式来传递
import React, { Component } from "react";
export default class Eventargu2 extends Component {
constructor(props) {
super(props);
this.state = {
money: 0
};
}
changeMoney = val => {
this.setState({
money: val
});
};
render() {
const { money } = this.state;
return (
<div>
<button onClick={this.changeMoney.bind(this, 5555)}>
{" "}
在`render`里通过`this.handleEvent.bind(this, 参数)`这样的方式来传递{" "}
</button>
<p> money有:{money} </p>
</div>
);
}
}
-
- 通过
event
传递处理用户输入
- 通过
import React, { Component } from "react";
export default class UserInput extends Component {
constructor(props) {
super(props);
this.state = {
firstName: "",
lastName: ""
};
}
getVal = ev => {
this.setState({
[ev.target.name]: ev.target.value
});
};
render() {
const { firstName, lastName } = this.state;
return (
<div>
姓: <input type="text" name="firstName" onInput={this.getVal} />
<hr />
名: <input type="text" name="lastName" onInput={this.getVal} />
<p>
欢迎:{firstName} {lastName}
</p>
</div>
);
}
}
- 比较推荐的是做一个子组件, 在父组件中定义方法,通过
props
传递到子组件中,然后在子组件件通过this.props.method
来调用
ref 绑定:
建议不要过量使用 ref , 会导致性能的浪费
-
普通绑定
<input type="text" ref="user" />
-
函数形式 - 推荐(减少一次系统查找)
<input type="text" ref={el => (this.user = el)} />
案例
import React, { Component } from "react";
import Hello from "./Hello";
export default class RefComp extends Component {
getRef = () => {
console.log("ref", this);
this.refs.ele.style.background = "red";
this.item.style.background = "yellow";
};
render() {
return (
<div>
<button onClick={this.getRef}>get ref 链</button>
<p ref="ele"> 今天周四了,一周要过去了 </p>
<Hello ref="comp"></Hello>
<p ref={el => (this.item = el)}>ref 函数形式</p>
</div>
);
}
}
组件通信
1. 父子组件通信
无论父组件传递是 props 还是 state,子组件都是通过 props 接收
- 父组件在子组件标签上写属性传餐
// Father.jsx
import React, { Component } from "react";
import Son from "./Son";
export default class Father extends Component {
constructor(props) {
super(props);
this.state = {
money: 2000
};
}
render() {
const { money } = this.state;
return (
<div>
<Son money={money} />
</div>
);
}
}
- 子组件用 this.props 接收参数
// Sonn.js
import React, { Component } from "react";
export default class Son extends Component {
render() {
const { money } = this.props;
return (
<div>
<p> 老爸给了我 {money} 生活费 </p>
</div>
);
}
}
- 子父组件通信
父组件传递方法给子组件,子组件调用父组件传递过来的方法
注意: 自己的状态自己更改 - 父组件把操作自身的属性的事件处理程序 以属性的形式发给子组件
//Father.jsx
import React, { Component } from "react";
import Son from "./Son";
export default class Father extends Component {
constructor(props) {
super(props);
this.state = {
money: 0
};
}
handle = val => {
// 定位
this.setState({
money: val
});
};
render() {
const { money } = this.state;
return (
<div>
<Son handle={this.handle}></Son> //定位
<p>儿子给我了:{money} 块钱</p>
</div>
);
}
}
- 子组件以 this.props 接收参数父组件的, 在一定条件下 执行父组件的事件处理程序 并进行传参
//Son,jsx
import React, { Component } from "react";
export default class Son extends Component {
constructor(props) {
super(props);
this.state = {
letter: 88888
};
}
render() {
const { handle } = this.props;
const { letter } = this.state;
return (
<div>
<button
onClick={() => {
handle(letter);
}}
>
发红包
</button>
</div>
);
}
}
非父子组件通信
- 父组件定义 事件处理函数,并将其发送给 出发地组件
// Father.jsx
import React, { Component } from "react";
import Son from "./Son";
import Girl from "./Girl";
export default class Father extends Component {
kick = () => {
//? 定义改变son组件的事件处理函数
this.son.changeFlag(); //todo 改变son组件的事件处理函数
};
render() {
return (
<div>
<h4>这里是Father</h4>
{/* 将事件处理函数发给girl组件 */}
<Girl kick={this.kick} />
<Son ref={el => (this.son = el)} />
</div>
);
}
}
- 出发地组件 通过 this.props 组件接收 父组件的事件处理函数,并在一定条件下操作,触发父组件的事件处理函数
//Girl.jsx
import React, { Component } from "react";
export default class Girl extends Component {
render() {
const { kick } = this.props; //? girl 组件 接收父组件发过来的 事件处理函数
return (
<div>
<h4>这里是girl</h4>
{/* 在一定条件下执行父组件的事件处理函数 */}
<button onClick={kick}> 揍弟弟 </button>
</div>
);
}
}
- 目的地组件 用 ref 的定义 ,父组件的事件处理函数运行 通过 this.refs 找到并操作目的地组件
//Son.jsx
import React, { Component } from "react";
export default class Son extends Component {
constructor(props) {
super(props);
this.state = {
flag: false
};
}
changeFlag = () => {
//todo son 组件自身的事件处理函数
this.setState({
flag: true
});
};
render() {
const { flag } = this.state;
return (
<div>
<h4>这里是Son</h4>
{(flag && <h3>哭哭哭哭哭</h3>) || <h3>笑</h3>}
</div>
);
}
}
跨组件通信
在 react 没有类似 vue 中的事件总线来解决这个问题,我们只能借助它们共同的父级组件来实现,将非父子关系装换成多维度的父子关系。react 提供了
context
api 来实现跨组件通信, React 16.3 之后的context
api 较之前的好用。
- 1.首先创建上下文 const MoneyContext = createContext( 默认值 )
? 在目的地组件 static 中 以属性 context 接收 moneyContext 并通过 this.context 来使用
? 在出发地组件创建<moneyContext.provider > 并以 value 属性进行传参
import React, { Component, createContext } from "react";
//* 1.首先引入createContext方法 并创建上下文 const MoneyContext = createContext( 默认值 )
const moneyContext = createContext(0);
//? 在目的地组件static 中 以属性context 接收moneyContext 并通过this.context 来使用
class Son extends Component {
//? 子组件
static contextType = moneyContext;
render() {
return (
<div>
<h4>这里是子组件</h4>
<p>爷爷给了我{this.context}钱</p>
</div>
);
}
}
class Father extends Component {
//? 父组件
render() {
return (
<div>
<h4>这里是父组件</h4>
<Son></Son>
</div>
);
}
}
//? 在出发地组件创建<moneyContext.provider > 并以value属性进行传参
export default class Stride extends Component {
//? 祖父组件
constructor(props) {
super(props);
this.state = {
money: 8888
};
}
render() {
const { money } = this.state;
return (
<div>
<h4>这里是Grandfather组件</h4>
<moneyContext.Provider value={money}>
<Father></Father>
</moneyContext.Provider>
</div>
);
}
}