复习
- 构造函数: https://blog.csdn.net/weixin_41796631/article/details/82939585
- 解构赋值: https://www.jianshu.com/p/d4a3baeac680
- 箭头函数
- this
- 事件
状态的修改
构造函数的解释:contructor的理解
- 这里的props参数是什么?
! props就是父组件绑定在子组件身上的属性
- 这里super( props ) 做了什么?
! 继承, 它将 props 属性赋值给 this.props
-
状态修改
-
事件:事件源,事件类型,事件处理程序( 1. 事件处理程序我们是直接定义为实例方法
2. 事件处理程序我们建议写成箭头函数 - this指向不改变)
-
修改状态
- 在React中状态的修改只能使用setState()
- setState() 的作用是用来更新视图的
- setState是异步的
- setState( obj/function, callback ) 参数是有两个的
- 第一个参数是用来修改状态的,可以是Object/function
- function必须要有返回值
- 第二个参数是一个回调函数,可以说是一个由数据改变而引起的副作用执行
- 第一个参数是用来修改状态的,可以是Object/function
- React中为一个可以更新视图的就是setState
-
示例一
import React, { Component } from 'react' export default class StateComp extends Component { constructor(props) { super(props) this.state = { info: 'React是前端流行的三大框架之一' } } // state = { // info: 'Hello React' // } changeState = () => { /* ! 参数是对象 this.setState({ info: '千锋教育' }) */ // 参数是方法 - 方法时必须要有返回值的,返回值是对象 this.setState(() => { console.log( 1 ) return { info: '前端无情' } },() => { console.log( 2 ) document.querySelector('span').style.background = 'red' }) console.log( 3 ) } render() { return ( <div> <button onClick = { this.changeState } > change state </button> <p>state的定义 { this.state.info } </p> <span> info变化了 </span> </div> ) } }
-
示例二
import React, { Component } from 'react' export default class StateDemo extends Component { constructor(props) { super(props) this.state = { arr: [ 1, 2,3 ] } } addItem = () => { //修改状态了 this.setState(() => { this.state.arr.push( 4 ) return { arr: this.state.arr } }) } render() { const { arr } = this.state return ( <div> <button onClick = { this.addItem }> + 4 </button> <ul> { arr.map( (item,index) => <li key = { index } > { item } </li>) } </ul> </div> ) } }
-
属性与状态
数据最好是由外传到内–多用props
相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)
不同点:
- 属性能从父组件获取,状态不能
- 属性可以由父组件修改,状态不能
- 属性能在内部设置默认值,状态也可以
- 属性不在组件内部修改,状态要改 【 属性只能外部修改,内部不允许修改】
- 属性能设置子组件初始值,状态不可以
- 属性可以修改子组件的值,状态不可以
state
的主要作用是用于组件保存、控制、修改自己的可变状态。state
在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state
是一个局部的、只能被组件自身控制的数据源。state
中状态可以通过 this.setState
方法进行更新,setState
会导致组件的重新渲染。
**props
的主要作用是让使用该组件的父组件可以传入参数来配置该组件**。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props
,否则组件的 props
永远保持不变。
如果搞不清 state
和 props
的使用场景,记住一个简单的规则:尽量少地用 state
,多用 props
。
没有 state
的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件(stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。
无状态组件也就是函数式组件
有状态组件就是类组件
经验:
功能复杂,我们使用类组件
功能单一,我们使用函数式组件
组件props要想变,那么就外部修改
组件state要想变,那么组件内部自身通过setState修改
react性能优化一个方案: 就是多使用无状态组件( 函数式组件 )
状态提升
- 如果有多个组件共享一个数据,把这个数据放到共同的父级组件中来管理
受控与非受控组件
-
React组件的数据渲染是否被调用 是通过 传递过来的
props
完全控制,控制则为受控组件,否则非受控组件。 -
示例:
Father.js import React, { Component } from 'react' import ControlledComp from './ControlledComp'; import UnControlledComp from './UnControlledComp'; export default class Father extends Component { constructor(props) { super(props) this.state = { flag : true, money:100 } } changeFlag = () => { this.setState({ flag:!this.state.flag }) } render() { const {flag} = this.state const {money } = this.state return ( <div> <button onClick = {this.changeFlag}>change flag</button> <ControlledComp flag = { flag }/> <UnControlledComp money = {money}/> </div> ) } }
//受控组件 import React, { Component } from 'react' export default class ControlledComp extends Component { render() { const { flag } = this.props return ( <div> <p> {flag ? '❤️取消' : '🖤收藏'}</p> <p> {flag && '❤️取消' || '🖤收藏'}</p> </div> ) } }
//非受控组件 import React, { Component } from 'react' export default class UnControlledComp extends Component { render() { const { money } = this.props return ( <div> <p> 给了我 { money } </p> </div> ) } }
渲染数据
-
条件渲染
<p> {flag ? '❤️取消' : '🖤收藏'}</p> <p> {flag && '❤️取消' || '🖤收藏'}</p>
-
列表渲染
import React,{Component} from 'react' export default class ListComp extends Component{ constructor(props){ super(props) this.state = { list:[ { id: 1, shop_name: '汽车' }, { id: 2, shop_name: '衣服' } ] } } renderItem = () =>{ const { list } = this.state return list.map(item => <li key = {item.id}>{item.shop_name}</li>) } render(){ return( <div> <ul> { this.renderItem() } </ul> </div> ) } }
事件处理
绑定事件
- 采用on+事件名的方式来绑定一个事件,注意,这里和原生的事件是有区别的,原生的事件全是小写
onclick
, React里的事件是驼峰onClick
,React的事件并不是原生事件,而是合成事件。
事件handler的写法 (4种)
-
直接在render里写行内的箭头函数(不推荐)
- 示例:
import React, { Component } from 'react' export default class EventOneComp extends Component { render() { return ( <div> <button onClick = {() => { alert( 1 ) }}> render中直接写箭头函数 </button> </div> ) } }
-
在组件内使用箭头函数定义一个方法(推荐)
-
示例:
import React, { Component } from 'react' export default class EventTwoComp extends Component { constructor(props) { super(props) this.state = { money: '10000' } } changeMoney = () => { this.setState({ money: '15000' }) } render() { const { money } = this.state return ( <div> <button onClick = { this.changeMoney }> change Money </button> <p> { money } </p> </div> ) } }
-
-
直接在组件内定义一个非箭头函数的方法,然后在render里直接使用
onClick={this.handleClick.bind(this)}
(不推荐)-
示例:
import React, { Component } from 'react' export default class EventThirdComp extends Component { constructor(props) { super(props) this.state = { money: 15000 } } changeMoney () { this.setState({ money: 20000 }) } render() { const { money } = this.state return ( <div> <button onClick = { this.changeMoney.bind( this ) }> change Money2 </button> <p> { money } </p> </div> ) } }
-
-
直接在组件内定义一个非箭头函数的方法,然后在constructor里bind(this)(推荐)
-
示例:
import React, { Component } from 'react' export default class EventFourComp extends Component { constructor(props) { super(props) this.state = { flag: true } this.changeFlag = this.changeFlag.bind( this ) } changeFlag () { this.setState({ flag: !this.state.flag }) } render() { const { flag } = this.state return ( <div> <button onClick = { this.changeFlag }> change flag </button> <p> { flag ? '❤️取消' : '🖤收藏' } </p> </div> ) } }
-
-
注意: 事件不能定义在函数式组件中
Event对象
- 和普通浏览器一样,事件handler会被自动传入一个
event
对象,这个对象和普通的浏览器event
对象所包含的方法和属性都基本一致。不同的是 React中的event
对象并不是浏览器提供的,而是它自己内部所构建的。它同样具有event.stopPropagation
、event.preventDefault
这种常用的方法 - 事件对象中的值很多都是null,但是可以正常使用
- e.target
事件参数的传递
-
在
render
里调用方法的地方外面包一层箭头函数-
示例:
import React, { Component } from 'react'
export default class EventArguOneComp 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( 100 ) }}> change money </button> <p> money有:{ money } </p> </div> ) }
}
-
-
在
render
里通过this.handleEvent.bind(this, 参数)
这样的方式来传递-
示例:
import React, { Component } from 'react' export default class EventArguTwoComp 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, 10000 ) }> change money </button> <p> money有: { money } </p> </div> ) } }
-
-
通过
event
传递 -
比较推荐的是做一个子组件, 在父组件中定义方法,通过
props
传递到子组件中,然后在子组件件通过this.props.method
来调用
处理用户输入
-
import React, { Component } from 'react' export default class UserInputComp extends Component { constructor(props) { super(props) this.state = { firstName: '', lastName: '' } } getVal = ( e ) => { this.setState({ [ e.target.name ]: e.target.value }) } render() { const { firstName,lastName } = this.state return ( <div> 姓: <input type = "text" name = "firstName" onChange = { this.getVal }/> <hr/> 名: <input type = "text" name = "lastName" onChange = { this.getVal }/> <p> 欢迎:{ firstName } { lastName } </p> </div> ) } }
-
ref绑定
-
建议不要过量使用ref , 会导致性能的浪费
普通绑定
函数形式 - 推荐
<input type=“text” ref = { el => this.user = el }/>
组件通信
父子组件通信
-
无论父组件传递是props还是state,子组件都是通过props接收
-
示例:
-
father import React, { Component } from 'react' import Son from './Son'; export default class Father extends Component { constructor(){ super() this.state = { money: 200 } } render() { const { money } = this.state return ( <div> <Son money = {money}/> </div> ) } }
-
son import React, { Component } from 'react' export default class Son extends Component { render() { const {money} = this.props return ( <div> <p> 爸爸给了:{money}</p> </div> ) } }
子父组件通信
-
父组件传递方法给子组件,子组件调用父组件传递过来的方法
注意: 自己的状态自己更改
-
示例:
-
father import React, { Component } from 'react' import Son from './Son' export default class Father extends Component { constructor(props) { super(props) this.state = { money: 0 } } handler = ( val ) => { this.setState({ money: val }) } render() { const { money } = this.state return ( <div> <Son handler = { this.handler }/> <p> 儿子给了我 { money } </p> </div> ) } }
-
son import React, { Component } from 'react' export default class Son extends Component { constructor(props) { super(props) this.state = { hongbao: 8000 } } render() { const { handler } = this.props const { hongbao } = this.state return ( <div> <button onClick = {() => { handler( hongbao ) }}> git 老爸 红包 </button> </div> ) } }
非父子组件通信
-
ref链
-
ref = ‘xxx’ this.refs.xxx
-
ref = { el => this.xxx = el } this.xxx 【 推荐 】
-
-
father import React, { Component } from 'react' import Son from './Son' import Girl from './Girl' export default class Father extends Component { kick = () => { this.son.changeFlag() } render() { return ( <div> <Girl kick = { this.kick }/> <Son ref = { el => this.son = el }/> </div> ) } }
-
import React, { Component } from 'react' export default class Girl extends Component { render() { const { kick } = this.props return ( <div> <button onClick = { kick }> 揍弟弟 </button> </div> ) } }
-
son import React, { Component } from 'react' export default class Son extends Component { constructor(props) { super(props) this.state = { flag:false } } changeFlag =()=>{ this.setState({ flag:true }) } render() { const {flag} = this.state return ( <div> { flag && <p> o(╥﹏╥)o</p> } </div> ) } }
跨组件通信
context
使用流程
- 创建上下文 React.createContext()
- 使用上下文包裹目标组件的父组件
<MoneyContext.Provider value = { money }>
<Father></Father>
</MoneyContext.Provider>
- 在目标组件中先定义一个静态属性 static contextType = MoneyContext
-
通过 this.context来使用数据
-
import React, { Component,createContext } from 'react' // const MoneyContext = createContext( 默认值 ) const MoneyContext = createContext( 0 ) class Father extends Component{ render () { return ( <div> father <Son/> </div> ) } } class Son extends Component{ static contextType = MoneyContext render () { return ( <div> son <p> 爷爷给了我 { this.context } </p> </div> ) } } export default class Stride extends Component { constructor(props) { super(props) this.state = { money: 100000 } } render() { const { money } = this.state return ( <div> <h3> 爷爷 </h3> <MoneyContext.Provider value = { money }> <Father/> </MoneyContext.Provider> </div> ) } }
-