目录
1、state是内部属性,props是为了更好地实现复用性,从外部接收数据
4、函数式组件对于属性的应用会更简单一些,直接通过形参可以获得
3、在父组件中对子组件进行ref标记,可以获取到子组件的引用
一、状态 :state
1、组件的状态
(1)有状态组件:设置了state的组件称之为有状态组件。 eg:类组件
(2)无状态组件:没有设置state的组件称之为无状态组件 eg:函数组件
2、组件中的数据
class A extends Component{ state = {key:value} }
class A extends Component{ constructor(){ super(); this.state = { key:value } } }3、在类中定义state(只能写这个名字)对象
state = {key:value}
注意:<1>不要直接修改state(状态)
//错误写法 this.state.comment = 'ok'<2>要使用 this.setState()来更新state
//正确写法 //this.setState({key:value}) this.setState({comment: 'ok'});4、使用setState要注意:
(1)在同步逻辑中,异步更新状态与真实dom
import React, { Component } from 'react' export default class App extends Component { state={ count:1 } render() { return ( <div> {this.state.count} <button onClick={this.handleClick}>同步逻辑button> <button onClick={this.handleClick2}>异步逻辑button> div> ) } handleClick=()=>{ this.setState({ count:this.state.count+1 }) console.log(this.state.count); this.setState({ count:this.state.count+1 }) console.log(this.state.count); this.setState({ count:this.state.count+1 }) console.log(this.state.count); } }(2)在异步逻辑中,同步更新状态与真实dom
import React, { Component } from 'react' export default class App extends Component { state={ count:1 } render() { return ( <div> {this.state.count} <button onClick={this.handleClick}>同步逻辑button> <button onClick={this.handleClick2}>异步逻辑button> div> ) } handleClick2=()=>{ setTimeout(()=>{ this.setState({ count:this.state.count+1 }) console.log(this.state.count); this.setState({ count:this.state.count+1 }) console.log(this.state.count); this.setState({ count:this.state.count+1 }) console.log(this.state.count); },0) } }(3)接受第二个参数,是个回调函数,在这里状态与dom更新完毕
handleClick = ()=>{ this.setState({ count:this.state.count+1 },()=>{ console.log(this.state.count) }) this.setState({ count:this.state.count+1 },()=>{ console.log(this.state.count) }) this.setState({ count:this.state.count+1 },()=>{ console.log(this.state.count) // 状态和真实dom已经更新完毕 }) }二、属性:props(只读)
1、state是内部属性,props是为了更好地实现复用性,从外部接收数据
//父组件 <MyNav title={this.title} /> //MyNav.js组件 render(){ return ( <div> <p>{this.props.title}<p/> div> ) }2、某组件
{/*属性*/} <MyNav title={this.title} leftBtn={isShowLeft}/>3、MyNav.js
render(){ let {title,leftBtn}=this.props; return ( <div> {leftBtn && <button>leftbutton>} <p>{title}p> <button>rightbutton> div> ) }(1)属性验证
import myprop from 'prop-types' static propTypes={ title:myprop.string, letBtn:myprop.bool }(2)默认属性
//默认属性 static defaultProps={ title:'首页' }4、函数式组件对于属性的应用会更简单一些,直接通过形参可以获得
三、属性及状态总结
1、属性是父组件对子组件的数据传输与操作
2、状态是组件自己内部的数据
四、表单
1、受控表单元素
(1)由React控制
(2)value绑定state中的值
(3)实现表单元素的change事件
(4)优化:可以使用name属性,统一完成change事件
(5)注意:选择框与其他表单元素获取值的方式不一样
class App extends React.Component { state = { txt: '', content: '', city: 'bj', isChecked: false } handleChange = e => { this.setState({ txt: e.target.value }) } // 处理富文本框的变化 handleContent = e => { this.setState({ content: e.target.value }) } // 处理下拉框的变化 handleCity = e => { this.setState({ city: e.target.value }) } // 处理复选框的变化 handleChecked = e => { this.setState({ isChecked: e.target.checked }) } render() { return ( <div> {/* 文本框 */} <input type="text" value={this.state.txt} onChange={this.handleChange} /> <br/> {/* 富文本框 */} <textarea value={this.state.content} onChange={this.handleContent}>textarea> <br/> {/* 下拉框 */} <select value={this.state.city} onChange={this.handleCity}> <option value="sh">上海option> <option value="bj">北京option> <option value="gz">广州option> select> <br/> {/* 复选框 */} <input type="checkbox" checked={this.state.isChecked} onChange={this.handleChecked} /> div> ) } }2、非受控表单元素
(1)由DOM控制
(2)在constructor中React.createRef()
class App extends React.Component { constructor() { super() // 1.创建ref this.txtRef = React.createRef() } // 获取文本框的值 getTxt = () => { // 3. 通过ref对象来获得表单元素的值 console.log('文本框值为:', this.txtRef.current.value); } render() { return ( <div> // 2.将创建好的 ref 对象添加到表单元素中 <input type="text" ref={this.txtRef} /> <button onClick={this.getTxt}>获取文本框的值button> div> ) } }五、通信
1、父传子:属性值
(1)父组件提供传递的数据
(2)给子组件标签添加属性,值为state中的数据
(3)子组件中通过props接收父组件中传过来的数据
// 子组件 export class tab extends Component { render() { return ( <div> {this.props.msg} div> ) } } // 父组件 export class exer extends Component { state = { mesg: 'msg', } render() { return ( <div> <tab msg={this.state.mesg} /> div> ) } }2、子传父:回调函数
(1)父组件提供一个回调函数,用于接收数据
(2)将函数作为属性的值,传给子组件
(3)子组件通过props调用回调函数
(4)将子组件中的数据作为参数传给回调函数
// 子组件 export class tab extends Component { render() { return ( <div> <p onClick={() =>{ this.props.changeMes("返回数据") } } >tabp> div> ) } } // 父组件 export class exer extends Component { state = { mesg: 'msg', } changemes = (newmsg) => { this.state({ meg: newmsg }) } render() { return ( <div> <tab changeMes={this.changemes} /> div> ) } }3、在父组件中对子组件进行ref标记,可以获取到子组件的引用
4、中间人模式:由父组件充当中间人,利用子传父+父传子模式完成
(1)公共父组件提供共享状态,提供共享状态的方法
(2)要接收数据状态的子组件通过 props 接收数据
(3)要传递数据状态的子组件通过props接收方法,调用方法传递数据
5、发布订阅模式
let bus = { list:[], //存放订阅者 //订阅者 subscrible(cb){ this.list.push(cb); }, //发布者 publish(text){ this.list.forEach(cb => cb && cb(text)) } }6、context状态树传参(官方提供)
(1)父组件
<GlobalContext.Provider value = { {a:1,b:2} }> <Child1>Child1> <Child2>Child2> GlobalContext.Provider>(2)子组件
<GlobalContext.Consumer> { value =>{ return ( <div>子组件{value}div> ) } } GlobalContext.Consumer>注意:value是固定的关键词
7、Redux:这个后面会讲到
六、插槽
1、默认形式
(1)父组件
<Child>插入任意内容
Child>(2)子组件
return ( <div> <p>子组件内部标签p> {/* 以下内容是插槽内容,外部代码在此进行替代 */} {this.props.children} {/* 固定写法 */} div> )2、按顺序插入
父组件: <Child>西游记
红楼梦
水浒传
Child> 子组件Child: return ( <div> {this.props.children[0]} {this.props.children[1]} {this.props.children[2]} div> )3、作用
(1)提高代码的复用性
(2)一定程度上减少父子通信
七、生命周期(钩子函数)
1、初始化阶段
(1)componentWillMount
<1>组件即将挂载,render之前最后一次修改state的机会
<2>常用于:state的初始化
<3>注意:如果有警告,可使用UNSAFE_componentWillMount
(2)render(渲染):只能访问props与state,不能修改state及进行dom输出
(3)componentDidMount
<1>成功执行完毕render并完成dom节点的渲染,可以对dom修改
<2>常用于:axios请求,订阅函数调用,计时器,dom操作
2、运行中阶段
(1)componentWillReceiveProps(nextProps)
<1>父组件修改属性触发
<2>最先获取父组件传来的属性,可以在这里进行axios请求或者其他逻辑处理
<3>注意:如果有警告,可使用UNSAFE_componentWillReceiveProps
(2)shouldComponentUpdate(nextProps,nextState)
<1>返回false,会阻止render的调用
<2>参数是被修改之后的新的属性及状态
(3)componentWillUpdate
<1>组件将要更新,不能修改该属性及状态
<2>注意:如果有警告,可使用UNSAFE_componentWillUpdate
(4)render(渲染):只能访问props与state,不能修改state及进行dom输出
(5)componentDidUpdate(preProps,preState)
<1>可以修改dom
<2>参数是被修改之前的属性及状态
3、销毁阶段
(1)componentWillUnmount
(2)在删除组件前进行清理工作
注意:写在前边:只有类组件(函数组件需要hooks支持)
八、新生命周期(推荐)
1、老钩子问题
componentWillmount会重复触发多少次,如果绑定事件无法解绑
2、static getDeriveStateFromProps(nextProps,nextState)
(1)将属性转为状态
(2)挂载之前于更新会执行
(3)返回一个状态对象