React---day8
9.6 不可变数据的力量
我们知道是不能够修改this.state里面的数据的
举个例子
export class App extends React.PureComponent{constructor(){super();this.state = {userList:[{name : "tom" , age : 18},{name : "lily" , age : 20},{name : "tiki" , age : 18},]}}render(){const userList =this.state.userListreturn (<div><ul>{userList.map((item , index , arr) => {return (<li key={index}>{item.name} + {item.age}</li>)})}</ul><button onClick={() => this.addNewUser()}>点击添加</button></div>)}
不推荐的做法:
const newData = {name : "hcy" , age : 19}this.state.userList.push(newData);this.setState({userList:this.state.userList})
因为我们修改了state里面的数据,但是这种方式直接修改原数组,不符合 React 的不可变性原则
我们的APP继承了PureComponent,它有shouldcomponnets方法,这个方法必须发生改变才会执行,但是我们这样的方法指向同一个地址(相同)所以是不会改变的
**推荐做法:**不要直接修改 state,应该用新数组。
const newData = {name : "hcy" , age : 19}this.setState({userList:[...this.state.userList , newData]//不要直接修改 state,应该用新数组。})
9.7 全局事件传递events
开发中跨组件之间的事件传递,使用events
通过npm或者yarn来安装events
npm add events
events常用的API:
- 创建EventEmitter对象:eventBus对象;
- 发出事件:eventBus.emit(“事件名称”, 参数列表);
- 监听事件:eventBus.addListener(“事件名称”, 监听函数);
- 移除事件:eventBus.removeListener(“事件名称”, 监听函数);
事件演练:
import React, { PureComponent } from 'react'
import {EventEmitter} from 'events'
// 需求:点击profile中的按钮->进行跨组件之间的事件传递
// 1、创建EventEmitter对象:eventBus对象
const evebtBus = new EventEmitter();export default class App extends PureComponent {render() {return (<div><Header /><Profile/></div>)}
}
class Header extends PureComponent{// 进行监听componentDidMount(){// 添加事件监听// 3、监听事件:eventBus.addListener("事件名称", 监听函数);// (eventName: string | symbol, listener: (...args: any[]) => void):// this.handleSayHelloListener:没有括号,因为是函数evebtBus.addListener("sayHello" , this.handleSayHelloListener)}componentWillUnmount(){// 取消事件监听// (...args: any[]) => void)// 4、 移除事件:eventBus.removeListener("事件名称", 监听函数);evebtBus.removeListener("sayHello" ,this.handleSayHelloListener)}// ...args// 多个参数要写多个形参handleSayHelloListener(str , num){console.log(str + num);}render (){return (<div>Hello World</div>)}
}
class Profile extends PureComponent{render (){return(<div>Hello Profile<button onClick={() => this.emmitEvent()}>点击Profile</button></div>)}
// 2、发出事件:eventBus.emit("事件名称", 参数列表);emmitEvent(){evebtBus.emit("sayHello" , "Hello Home" , 123)}
}
10、受控和非受控组件
10.1 refs的使用
- 方式一:传入一个对象
-
- 对象是通过 React.createRef() 方式创建出来的;
- 使用时获取到创建的对象其中有一个current属性就是对应的元素;
- 方式二:传入一个函数
-
- 该函数会在DOM被挂载时进行回调,这个函数会传入一个 元素对象,我们可以自己保存;
- 使用时,直接拿到之前保存的元素对象即可;
import React, { PureComponent } from 'react';
import Pure from './Pure';
export default class App extends PureComponent {constructor() {super();this.titleRef = React.createRef();this.titleEle = null;}render() {return (<div>{/* 1、React.createRef() */}<h2 ref={this.titleRef} >Hello World</h2>{/* 2、传入一个函数 */}<h2 ref={(args) => this.titleEle = args}>Hello World</h2><button onClick={() => this.changeRef()}>点击切换</button></div>);}changeRef() {this.titleRef.current.innerHTML = "Hello React";this.titleEle.innerHTML = "Hello React"}appAdd(){console.log(this.pureRef.current.btnAdd());}
}
10.2 ref的类型
ref 的值根据节点的类型而有所不同:
- 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性;
- 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性;
- 你不能在函数组件上使用 ref 属性,因为他们没有实例;
举一个组件上使用ref的例子:
// 组件的refthis.pureRef = React.createRef();{/* 3、当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性; */}<Pure ref={this.pureRef}/><button onClick={() => this.appAdd()}>app+1</button>
10.3 受控组件
受控组件是单元素(如<input>
、<textarea>
等)的值由React的state进行“控制”,即组件的状态(state)是唯一数据源。
import React, { PureComponent } from 'react'export default class App extends PureComponent {constructor(){super();this.state = {username:""}}render() {return (<div><form><input type='text'value={this.state.username}onChange={(e) => this.handleChange(e)}/><input type='submit'onClick={(e) => this.handleSubmit(e)}/></form></div>)}handleSubmit(event){event.preventDefault();console.log("提交内容:",this.state.username)}handleChange(event){this.setState({username:event.target.value})}
}
<input>
的 value
属性绑定了 this.state.username
,输入框的内容只能通过 setState
来改变。每当用户输入内容时,onChange
事件会触发 handleChange
,进而更新 state,React 再把最新的 state 赋值给 input 的 value。
总结:
受控组件的输入值受 React 组件的 state 控制,React 负责管理和同步表单数据,这就是“受控”的含义。
其他受控通过组件:比如select
import React, { PureComponent } from 'react'export default class App extends PureComponent {constructor(){super();this.state = {fruit:"apple"//默认为苹果}}render() {return (<div><form onSubmit={(e) => this.handleSubmit(e)}>{/* 选择器 */}<select value={this.state.fruit}name='fruits'onChange={(e) => this.handleChange(e)}><option value="apple">苹果</option><option value="oringe">橘子</option><option value="bannana">香蕉</option></select></form></div>)}handleSubmit(event){event.preventDefault();console.log("提交内容:",this.state.fruit)}handleChange(event){this.setState({fruit:event.target.value})}
}
受控组件—多输入
要是不抽取代码就会很冗余
import React, { PureComponent } from 'react'export default class App extends PureComponent {constructor(){super();this.state = {username:"",password:""}}render() {return (<div><form><input type='text'name='username'value={this.state.username}onChange={(e) => this.handleChange(e)}/><input name='password'type='password'value={this.state.password}onChange={(e) => this.handleChange(e)}/><input type='submit'onClick={(e) => this.handleSubmit(e)}/></form></div>)}handleSubmit(event){event.preventDefault();const {username , password } = this.state;console.log("提交内容:",username , password )}
// handleusernameChange(event){
// this.setState({
// username:event.target.value
// })// }
// handlepasswordChange(event){
// this.setState({
// password:event.target.value
// })// }handleChange(event){this.setState({[event.target.name] : event.target.value})}
// 我们可以把handleChange写为一个,因为她们的样式是都是:
// handle{key}Change(event){
// this.setState({
// {key}:event.target.value
// })// }
// 我们只需要动态更新key就好
// 1、input设置name
// 2、event.target.name得到不同的key
}
10.4 非受控组件的使用
如果要使用非受控组件中的数据,那么我们需要使用 ref 来从DOM节点中获取表单数据。
在非受控组件中通常使用defaultValue来设置默认值;
import React, { createRef, PureComponent } from 'react'export default class App extends PureComponent {constructor(){super();this.nameRef = createRef()//创建ref对象}render() {return (<div><form><input type='text'ref={this.nameRef}//绑定ref/><input type='submit'onClick={ this.handleSubmit}/></form></div>)}handleSubmit = (event) => {event.preventDefault();console.log("提交内容:",this.nameRef.current.value)}//箭头函数
}