REACT学习日志

目录

创建虚拟DOM

jsx

函数式组件(简单组件,无状态)

需求

 类式组件(复杂组件,有状态)

需求

实例组件三大属性(props、state、refs)

state--状态

setState

state、事件绑定简写

 Props

向组件传参数(只读)

批量传参

 传参限制

参数限制

 Props简写

函数组件的props

refs与事件处理 

 createRef(只存储一个)

事件绑定

事件绑定的this问题(简写在上)

事件处理

非受控组件(数据存在自己身上)// Uncontrolled:// Use `inputRef.current.value` to read the current value of

受控组建(双向数据绑定,数据绑定state)

高阶函数与函数柯里化

旧生命周期

挂载

更新

新生命周期

去除

添加

Diffing算法

脚手架

public——静态资源

src——文件

components——放置组件文件

react ajax

配置单个代理

配置多个代理

兄弟组件间交互——消息订阅与发布机制

路由

内置组件

其他

路由组件与一般组件 

路由的精准匹配与模糊匹配

嵌套路由

路由传参

路由跳转的两种模式

编程式路由导航

redux

React——Redux

纯函数

 setState更新状态两种写法

1、对象式

2、函数式

lazyLoad

Hooks

State Hook

Effect Hooks

Ref Hooks

Context

 Purecomponent

renderProps(类似插槽)

 通信方式总结



创建虚拟DOM

const VDOM= (

    html内容

)

ReactDom.render( VDOM, getElementById(' test '))

jsx

新的js扩展,创建虚拟dom的语法糖

  1. ()内写html
  2. {}内写可写js表达式
    1. 表达式:会产生一个值
    2. if,for不能用,改用filter,foreach,map
  3. 样式类名class-->className
  4. 内联样式,style={{key:value}}
  5. 虚拟DOM只有一个根标签
  6. 标签首字母小写

函数式组件(简单组件,无状态)

需求

  1. 组件首字母大写(区分函数和类)

返回值是虚拟DOM

function Demo(){
    return html代码
}
ReactDOM.render(<Demo/>,doucument.getElementById('test'))

 执行了ReactDOM.render

1、React解析组件标签,找到组件

2、发现是函数定义,调用函数,返回的虚拟DOM转换为真实DOM,随后呈现在页面中


 类式组件(复杂组件,有状态)

需求

  1. 必须继承React.Component
  2. 有render函数
class hello extends React.Component{

    render()
    {
        return <h1>hellow world</h1>
    }
    

}

ReactDOM.render(<hello/>,document.getElementById('test'))

 执行了ReactDOM.render

1、React解析组件标签,找到组件

2、发现是类定义,调用函数,new实例,通过该实例调用render方法

3、将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。


class People {

    constructor( name , age ){

        this.name = name
        
        }
    speak(){
        console.log( '!' )
    }
}

class Student extends Person {
    constructor(name,age,grade){

    super(name, age)
    this.grade=grade

    }
}
  1. 子类继承继承的是父类原型链上的东西
  2. 父类的方法都是在原型上
  3. 子类写了构造器,必须使用super,且在第一行

因为子类没有自己this指针,super相当于A.prototype.constructor.call(this, props)

super作为对象时,在普通方法中,指向父类的原型对象,在静态方法中,指向父类

类包含

1、方法

2、属性

3、state


实例组件三大属性(props、state、refs)

state--状态

class Weather extends React.Componets{
    //初始化状态
    constructor(props){

    super(props)
    this.state={isHot:true}

    }
    //渲染到页面
    render(){
    rerurn <h1>{this.state.isHot ? '炎热' : '凉爽' }</h1>
    }
}


ReactDOM.render(<Weather/>,document.getElementById('test'))

setState

只有通过setState修改,才会重新调用render,state才能修改在页面上

更新是一种合并,同名修改,不同名不管

class Weather extends React.Componets{
    //初始化状态
    constructor(props){

    super(props)
    this.state={isHot:true}
    this.changeWeather=this.changeWeather.bind(this)
    }
    //渲染到页面
    render(){
    rerurn <h1 onClick={demo}>{this.state.isHot ? '炎热' : '凉爽' }</h1>
    }

    changeWeather(){
        const isHot=!isHot
        this.setState({isHot:!isHot})
    }
}


ReactDOM.render(<Weather/>,document.getElementById('test'))

state、事件绑定简写

class Weather extends React.Componets{
    
    //直接写赋值语句就是在类上添加属性。
    a=1
    //由此可以简写
    state ={isHot :false,wind:'微风'}
    changeWeather=()=>{
     this.setState({isHot:!isHot})

    }
    render(){
    rerurn <h1 onClick={demo}>{this.state.isHot ? '炎热' : '凉爽' }</h1>
    }
    

}


ReactDOM.render(<Weather/>,document.getElementById('test'))

 自定义方法用赋值语句+箭头函数(箭头函数保证this指向外层实例)


 Props

向组件传参数(只读)

class Person extends React.Component {
    
    render(){
        return (
            <ul>
                <li>姓名:{this.props.name}</li>
            </ul>
        )
    }
}
ReactDom.render(</Person name='tom'>,,document.getElementById('test'))

向props中加入{ name: 'tom' }

批量传参

const p={name:'a',age:'12'}

ReactDOM.render(<Person { ...p } />).getElementById

 传参限制

  1. ' ' :  传入的是字符串
  2. {} :  传入的是数字
ReactDOM.render(<Person name='marry' age={19} />).getElementById

参数限制

//属性类型和必要性的限制
Person.propTypes={
    name:PropTypes.string.isRequired //传递的是字符串且必须
}

//属性默认值的限制
Person.defaultProps={
    sex:'男'    //默认值为男
}

 Props简写

class Person extends React.Component {
    
//属性类型和必要性的限制
static propTypes={
    name:PropTypes.string.isRequired //传递的是字符串且必须
}

//属性默认值的限制
static defaultProps={
    sex:'男'    //默认值为男
}
    render(){
        return (
            <ul>
                <li>姓名:{this.props.name}</li>
            </ul>
        )
    }
}
ReactDom.render(</Person name='tom'>,,document.getElementById('test'))

函数组件的props

function Person (props){
    
        return (
            <ul>
                <li>姓名:{props.name}</li>
            </ul>
        )
    }
}
ReactDom.render(</Person name='tom'>,,document.getElementById('test'))

refs与事件处理 

字符串形式的ref(老得)

refs:标识元素

class Demo extends React.Component{

    showData=()=>{
        console.log(this.refs.input)
    }
    render(){
        return(
            <div>
                <input ref ='input' />
                <button ref='button' onClick={this.showData}><button/>
            </div>
        )
    }
}

ref值放入refs{ }中,可直接从refs 中读取

回调模式的ref

class Demo extends React.Component{

    showData=()=>{
        const {input1} =this
        alert(input.value)
    }
    render(){
        return(
            <div>
                <input ref ={c => this.input1 = c } />
                <button ref='button' onClick={this.showData}><button/>
            </div>
        )
    }
}

回调函数将节点加入到this上,从this上获取节点 

 createRef(只存储一个)

class Demo extends React.Component{
    //调用后可以返回一个容器,该容器可以存储被Ref所标识的节点
    myRef =React.createRef()

    showData=()={
        console.log(this.myRef)
    }
    render(){
        return {
            <div>
                <input ref={this.myRef} /}
            </div>
        }
    }
}
  1. 创建容器
  2. 在节点处,将其放入容器 
  3. 使用时引用

事件绑定

事件绑定的this问题(简写在上)

class Weather extends React.Componets{
    //初始化状态
    constructor(props){

    super(props)
    this.state={isHot:true}
    this.changeWeather=this.changeWeather.bind(this)
    }
    //渲染到页面
    render(){
    rerurn <h1 onClick={demo}>{this.state.isHot ? '炎热' : '凉爽' }</h1>
    }

    changeWeather(){
        console.log(this)
    }
}


ReactDOM.render(<Weather/>,document.getElementById('test'))

类的局部函数都开起了严格模式,this指针直接调用时为undefined. 

若直接调用changeWeather则此时this为undefined,需要在构造器中指定this指向。 

 自定义方法用赋值语句+箭头函数(箭头函数保证this指向外层实例)


事件处理

1、通过onXxx来指定事件处理函数

2、通过event.target得到发生事件的DOM元素对象

非受控组件(数据存在自己身上)
// Uncontrolled:
<input type="text" defaultValue="foo" ref={inputRef} />
// Use `inputRef.current.value` to read the current value of <input>

现用现取

受控组建(双向数据绑定,数据绑定state)

// Controlled:
<input type="text" value={value} onChange={handleChange} />

随数据改变,维护状态改变


高阶函数与函数柯里化

高级函数:满足两者之一

        1、接受参数为函数

        2、返回值是函数

科里化:通过函数调用继续返回函数的方式,实现多次接受参数最后统一处理的函数编码方式

class login extends React.Component{

    state={
        username:'',
        password:''
    }
    saveFormData =(dataType)=>{
        return (event)=>{
            this.setState( {[dataType]:event.target.value } )        
        }
    }
    render(){
        return(
             <form onSubmit={this.handleSubmit}>
                用户名:<input onChange={this.saveFormData('username')} >
             </form>   
        )
    }
}

旧生命周期

挂载

  • constructor:
    • 构造器,万物之初
  • componentWillMount:
    • 组件将要挂载
  • render:
    • 渲染
  • componentDidMount:
    • 组件挂载完毕
  • componentWillUnmoount:
    • 组件将要被卸载

更新

  • componentWillRecieveProps:
    • 将要接受新参数时触发(第一次传的参数不算
  • shouldComponentUpdate:
    • 调用setState()时触发,返回值为真,则继续执行。返回为假,不再往后执行。不写默认为真是一个阀门
  • componentWillUpdate:
    • 组件将要更新
    • forceUpdate()强制更新,调用时触发此生命周期函数
  • render:
    • 渲染
  • componentDidUpdate:
    • 将要更新
  • componentWillUnmount:
    • 将要卸载

新生命周期

去除

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

添加

  • getDerivedStateFromProps(props,state)
    • 只能是静态方法
    • 返回值为新的状态对象或null
    • state的值不能再改变了,只能取决与props
  • getSnapshotBeforeUpdate(preProps,preState)
    • 更新之前获取快照,使得组件在更新之前获取一些数据
    • 返回值为(快照值)或null
    • 快照值,更新前的数据,传给componentDidUpdate
    • componentDidUpdate(preProps,preState,snapshot)

Diffing算法

key是虚拟dom的标识。在数据变化时,react会根据新数据生成新的虚拟dom,之后react进行虚拟dom,与旧虚拟 don的diff比较,规则如下

  1. 旧虚拟dom找到了与新虚拟dom相同的key:
    1. 若虚拟dom中内容没变,直接复用
    2. 若虚拟dom中的内容变化,生成新的真实dom,随后替换掉页面中之前的真实dom
  2. 旧虚拟dom中未找到与新虚拟dom相同的key
    1. 根据数据创建新的真实dom,随后渲染到页面

脚手架

public——静态资源

index.html:页面文件,用于被添加的节点

src——文件

index.js:入口文件。1、放置头文件资源。2、html渲染到public节点

App.js:组件外壳,放置组件

components——放置组件文件


react ajax

配置单个代理

package.jsion中的

proxy选项用于配置代理

配置多个代理

src中创建

setupProxy.js


兄弟组件间交互——消息订阅与发布机制

发送方:发布消息

PubSub.publish = function ( 'atguigu' , { name :LiHua , age : 18}  )

接收方:接受消息

PubSub.subscribe( 'atguigu' , (data)=>{ handle(data) } )

路由

内置组件

  • <BrowserRouter>
  • <HashRouter>
  • <Route>
    • 注册路由
    • 用Router包裹
    • <BrowserRouter>
          <Route path="path" component={component}/>
      </BrowserRouter>

  • <Redirect>
    • 都没匹配上之后,启动redirect(兜底方案)
    • <Switch>
          <Route path="" component={app}>
         
          <Redirect to = " path ">
      </Switch>

  • <Link>
    • <BrowserRouter>
          <Link className='' to='Path'>点我变化</Link>
      </BrowserRouter>
    • 必须用Router包裹(BrowserRouter/ HashRouter)
    • 路由跳转链接
  • <NavLink>
    • 点谁就给谁多加一个样式名
    • <NavLink activeName='激活的样式名' to="path"></NavLink>
  • <Switch>
    • 匹配上之后不会继续匹配,避免多重匹配效率低下
    • <Switch>
       <Route path=/about' component={About}>
       <Route path=/about' component={Text}>
      </Switch>

其他

  • history对象
  • match对象
  • withRouter函数
    • 一般组件没有this.history,让一般组件使用history
    • withRouter(component),之后component可以使用路由组件的api

路由组件与一般组件 

  1. 写法不同
    1. 一般组件:<Demo/>
    2. 路由组件:
      1. <Link to="path"> 
      2.  <Router path="path" component={Demo}>
  2. 存放位置不同
    1. 一般组件:component
    2. 路由组件:page
  3. 接受的props不同
    1. 一般组件:接受传递的参数
    2. 路由组件:接收到三个固定的属性
      1. history
      2. location
      3. match

路由的精准匹配与模糊匹配

模糊匹配:path = ”home/a/b“与path = “ home "可以匹配

严格匹配:<Route exact path="/about" component={ home }> 开启

嵌套路由

此时注册路由需要将前几级全部写上,保证最初路由能够匹配上

<MyNavLink to = "/home/news"> </MyNavLink>

<Route path="/home/news" component={Message}/>

路由传参

  1. params参数
    1. 路由链接(携带参数):<Link to=' /demo/text/tom/18 ' >详情</Link>
    2. 注册路由(声明接受):<Route path= " /demo/test/: name/:age" component={Test}/>
    3. 接收参数:this.props.match.params
  2. search参数
    1. 路由链接(携带参数):<Link to=' /demo/text?name=tom&age=18 ' >详情</Link>
    2. 注册路由(声明接受):<Route path= " /demo/test" component={Test}/>
    3. 接收参数:this.props.location.search
  3. state参数
    1. 路由链接(携带参数):<Link to=' /demo/text' , state:{name=tom&age=18 }>详情</Link>
    2. 注册路由(声明接受):<Route path= " /demo/test" component={Test}/>
    3. 接收参数:this.props.location.state

路由跳转的两种模式

  • push模式
  • replace模式
    • 开启replace模式
<Link replace to={{pathname = "path" , state:{a:a,b:b}}}>

编程式路由导航

this.props.history.replace("/home/detail")
this.props.history.push("/home/detail")

redux

集中管理组件中共享的状态

 action:动作对象

        type:动作类型

        data:动作数据

使用步骤

  1. 去除组件自身状态
  2. src下建立
    1. redux
      1. store.js
      2. count_reducer.js
      3. actionCreactor.js
  3. actionCreactor.js
    1. 创建action对象
    2. 处理 异步请求
  4. store.js:
    1. 引入redux中的createStore函数,创建一个store
    2. createStore调用时要传入一个为其服务的reducer
  5. conut_reducer:
    1. 本质是一个函数,接收两个参数(preState(之前状态),action(动作)),返回加工后的状态
    2. reducer有两个作用,初始化状态,加工状态
    3. reducer第一次调用时,是store自动触发的,传递的preState为undefined
  6. 在index.js中检测store状态的改变,一旦改变,重新渲染<APP/>

React——Redux

 使用步骤

  1. 两个组件
    1. UI组件:不使用任何redux的api,只负责页面的呈现交互
    2. 容器组件:负责和redux通信,将结果交给UI组件
  2. 创建容器组件——connect函数
    1. connect(mapStateToProps,mapDispatchToProps)(UI组件)
      1. mapStateToProps:返回值是一个对象,为redux状态
      2. mapDispatchToProps:返回值是一个对象,为redux方法
  3. 容器组件的store靠props传入,而非直接引入
  4. 可以不用自己检测状态改变

纯函数

Def:同样的输入,必定得到同样的输出(一样的参数,对应一样的返回)

遵守以下约束

  1. 不得改写参数数据
  2. 不会产生任何副作用
  3. 不能调用Date.now() Math.random() 等不纯的方法

redux的reducer必须是一个纯函数


 setState更新状态两种写法

1、对象式

this.setState(stateChange, callback)
  

 状态更新是异步的

stateChange:状态改变对象

callback:状态更新后调用的函数

2、函数式

this.setState(updater , callback)

updater:是函数,返回状态改变对象

updater(state,props)


lazyLoad

路由懒加载

引入部分

const Home = lazy( () => import ( "path" ) )

 路由注册部分(需要一个兜底方案)

 <Suspense fallback=> { 页面 } >

        <Router path=" path " component={Home}>

</Suspense>


Hooks

在函数式组件中使用state以及其他的react特性 

State Hook

  1. state hook 让函数组件也可以有state状态
  2. 语法:const [ xxx , setxxx ] = React.useState( initValue )
  3. useState( )说明:
    1. 参数:第一次初始化制定的值在内部作缓存
    2. 返回值:包含两个元素的数组,第一个为内部当前状态值,第二个为更新状态值的函数
  4. setxxx()两种写法
    1. setXxx(newValue):参数为非函数值,直接指定新的状态值,覆盖原来的值
    2. setXxx(value => newValue ):参数为函数,接收原来的值,返回新的状态值

Effect Hooks

在函数式组件中使用生命周期

  1. 语法:

React.useEffect( () => {

//DidMount 和 DidUpdata

        return () => {

                //willUnmount

        }       

} , [stateValue] ) //若指定[] 回调函数只会在第一次render后执行,其他情况则为监视[]值

Ref Hooks

在函数组件中引用元素

语法:const refContainer = useRef()


Context

用于组件间通信,用于祖宗组件与后代组件之间通信

步骤

  1. 创建Context容器对象
    1. const XxxContext = React.createContext( )
  2. 渲染子组件时,外面包裹xxxContext.Provider,通过value属性给后代传递数据
    <xxxContext.Provider value = {数据 }>
    
          子组件
    
    </xxxContext.Provider>
  3. 后代组件读取数据 

    //适用于类组件
    static contextType = xxxContext //声明接收context
    this.context //读取context中的数据
    
    //函数组件与类组件都可以
    <xxxContext.Consumer>
        {
            value => (value.xxx)
        }
    </xxxContext.Consumer>


 Purecomponent

当props、state不改变时,调用setState会重新刷新,效率低下。应该在shouldComponentUpdate(),中进行判断,只有当状态不同时才重新渲染。

pureComponent将这一部分逻辑封装,可以直接用pureComponent

export default class Parent extends PureComponent{ }

其中有一个问题,在比较时只浅比较,引用对象只比较地址。在对比引用对象时,应该避免与原对象相关。


renderProps(类似插槽)

有两种方法形成父子关系

1、父亲在jsx中调用子组件

2、在祖宗中 (想在编码时才确定父子关系时,可以这样调用)

        <A>

                <B/>

        </A>

此时可以通过this.props.chidren调用


 通信方式总结

  1. props
  2. 消息订阅与发布
  3. 集中式管理(redux)
  4. conText:生产者-消费者模式

父子组件:props

兄弟组件:消息订阅与发布、集中式管理

祖孙组件:消息订阅-发布、集中式管理、conText

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值