1.React是什么

React是一个构建用户界面的JavaScript库,用于实现组件化开发

2.什么是组件化

将一个复杂的页面分割成若干个独立的组件,每个独立组件各自有自己的业务逻辑以及样式,这样将一个复杂的页面独立分割成独立组件的方式就是组件化

特点:

  • 可组合

  • 可复用

  • 好维护

3.React由什么组成

React有两个核心库组成,分别为react.jsreact-dom.js,老版本只有react.js

  • react.js:是React的核心库

  • react-dom.js:用于提供与DOM相关功能,render方法用来向浏览器插入DOM元素

4.JSX

4.1什么是JSX

JSX可以理解为使用JS和HTML混合组成的一种语法,将组建的结构,数据以及样式组合在一起定义的组件,JSX其实只是一种语法糖,最终通过babeljs转译成createElement语法

JSX

 <div className='container'>
   <p style={{color:'#f00'}}></p>
   <button onClick={this.btnHandler}>submit</button>
 </div>

通过babeljs转译:

 "use strict";
 ​
 React.createElement("div", {
   className: "container"
 }, React.createElement("p", {
   style: {
     color: '#f00'
   }
 }), React.createElement("button", {
   onClick: (void 0).btnHandler
 }, "submit"));

createElement后:

 {
     "type":"div",
     "props":{
         "className":"container",
         "children":[
             {
                 "type":"p",
                 "props":{
                     "style":{
                         "color":"#f00"
                     },
                     "children":[
 ​
                     ]
                 }
             },
             {
                 "type":"button",
                 "props":{
                     "onClick":"btnHandler()",
                     "children":[
                         "submit"
                     ]
                 }
             }
         ]
     }
 }

注意:

如果createElement后的结果通过JSON.stringify()后onClick丢失,这里是为了更好的看create后的结果,通过JSON.stringify()转换,然后将OnClick手动添加上去的

4.2更新元素渲染

React元素都是immutable不可变的,当元素被创建完成之后,你是无法改变其内容和属性的。更新界面的唯一办法是创建一个新的元素,然后将它传入React.render()方法

 import React from 'react';
 import ReactDOM from 'react-dom';
 let num=0
 function counter() {
     const element = (
       <div>
         {num++}
       </div>
     );
     ReactDOM.render(element, document.getElementById('root'));
 }
 setInterval(counter, 1000);

4.3React只会更新变化的部分

ReactDOM首先会比较元素内容先后的不同,然后在渲染过程中只更新变化的部分,即使我们每秒都创建了一个描述整个UI树的新元素,ReactDOM也只会更新渲染文本节点中发生变化的内容

5.组件&Props

组件的创建方式有两种,一种是函数式组件,一种是类组件

组件类似于函数,接受任意的入参(props),并返回用于描述页面展示内容的React元素

5.1函数组件

 function Wellcome(props){
   return <div>hello,{props}</div>
 }

5.2类组件

 class Wellcome extends React.Component{
   render(){
     return (
       <div>hello,{this.props}</div>
     )
   }
 }

5.3Props的只读性

无论使用函数或者类声明的组件,它都不能修改自己的props

所有的React组件必须像纯函数那样使用它们的props

纯函数:

  • 如果函数的调用参数相同,则永远返回相同的结果。它不依赖于程序执行期间函数外部任何状态或数据的变化,必须只依赖于其输入参数

  • 该函数不会产生任何可观察的副作用

6.状态state

  • 组件的数据来源一个是属性对象,一个是状态对象

  • 属性是父组件传递过来的

  • 状态是组件自身的,改变状态的唯一方式是setState

  • 属性和状态的变化都会影响视图的更新

6.1.setState

改变属性的唯一方式setState,不能通过this.state=xxx

 class Counter extends React.Component{
   state={
     num:0
   }
 ​
   render(){
     const {num}=this.state
     return (
       <>
         <p>{num}</p>
         <button onClick={()=>this.setState({num:num+1})}>增加</button>
       </>
     )
   }
 }
 ​
 ReactDOM.render(<Counter/>,document.getElementById('root'))

6.2.State的更新可能是异步的

  • 为了优化性能,React可能会把多个setState()调用合并为一个调用

  • 如果要依赖更新完成的值,我们可以通过setState(state=>(),()=>{})方式

 class Counter extends React.Component{
   state={
     num:0
   }
 ​
   add=()=>{
 ​
     this.setState({num:this.state.num+1})
     console.log('a',this.state.num)//0
 ​
     this.setState({num:this.state.num+1})
     console.log('b',this.state.num)//0
 ​
     this.setState(state=>(
       {num:state.num+1}
     ),()=>{
       console.log('c',this.state.num)//3
     });
 ​
     this.setState(state=>(
       {num:state.num+1}
     ),()=>{
       console.log('d',this.state.num)//3
     });
 ​
   }
 ​
   render(){
     const {num}=this.state
     return (
       <>
         <p>{num}</p>
         <button onClick={this.add}>增加</button>
       </>
     )
   }
 }
 ​
 ReactDOM.render(<Counter/>,document.getElementById('root'))

6.3数据是单向向下流动

React中state只会影响自己或者依赖它的子组件

7.事件处理

  • React的事件是通过驼峰命名的

  • 使用JSX语法时,需要传入函数,而不是string

  • 不能通过false阻止事件默认行为,event.preventDefault阻止

class Counter extends React.Component{
  add=(event)=>{
    event.preventDefault()
  }
  render(){
    return (
      <>
        <button onClick={this.add}>增加</button>
      </>
    )
  }
}

7.1.this

回调中的this

  • 箭头函数

  • 匿名函数

  • bind进行绑定

class HandlerThisCom extends React.Component{
  constructor(props){
    super(props)
  }
   add1(event){
    event.preventDefault()
    console.log('add1')
  }

   add2=(event)=>{
    event.preventDefault()
    console.log('add2')
  }

  render(){
    return (
      <>
        <button onClick={this.add1.bind(this)}>button1</button>
        <button onClick={this.add2}>button1</button>
        <button onClick={event=>{
          event.preventDefault()
          console.log('add3')
        }}>button1</button>
      </>
    )
  }
}

ReactDOM.render(<HandlerThisCom/>,document.getElementById('root'))

7.4 Ref

React为了方位DOM节点,提供了Ref

Ref三种创建方式:

  • ref的值是一个字符串

  • ref的值是一个函数

  • ref为React.createRef()

class RefCom extends React.Component{
  constructor(props){
    super(props)
    this.emailRef=React.createRef()
  }

  getNameHandler=()=>{
    const name=this.refs.name.value
    console.log(name)
  }

  getPwsHandler=()=>{
    const psw=this.psw.value
    console.log(psw)
  }

  getEmailHandler=()=>{
    const email=this.emailRef.current.value
    console.log(email)
  }
  render(){
    return (
      <>
        <div>
          <input ref='name'/>
          <button onClick={this.getNameHandler}>获取名字</button>
        </div>
        <div>
          <input ref={input=>this.psw=input}/>
          <button onClick={this.getPwsHandler}>获取密码</button>
        </div>
        <div>
          <input ref={ this.emailRef}/>
          <button onClick={this.getEmailHandler}>获取密码</button>
        </div>
      </>
    )
  }
}

ReactDOM.render(<RefCom/>,document.getElementById('root'))

7.5.forwardRef转发

  • 不能在函数组件上使用ref,因为没有实例

  • Ref转发是将ref自动通过组件传递给子组件的

class Form extends React.Component {
  constructor(props){
      super(props);
      this.input = React.createRef();
  }
  getFocus = () => {
      this.input.current.focus();
  }
  render() {
      return (
          <>
            <TextInput ref={this.input}/>
            <button onClick={this.getFocus}>获得焦点</button>
          </>
      );
  }
}
const TextInput =React.forwardRef((props,ref)=>(
  <input ref={ref}/>
))

ReactDOM.render(<Form/>,document.getElementById('root'))

forwardRef的实现原理

class Form extends React.Component {
  constructor(props){
      super(props);
      this.input = React.createRef();
  }
  getFocus = () => {
      this.input.current.focus();
  }
  render() {
      return (
          <>
            <TextInput myref={this.input}/>
            <button onClick={this.getFocus}>获得焦点</button>
          </>
      );
  }
}
const TextInput =forwardRef((props,ref)=>(
  <input ref={ref}/>
))

function forwardRef(funcComponent){
  return function(props){
      let ref = props.myref;
      return funcComponent(props,ref);
  }
}

ReactDOM.render(<Form/>,document.getElementById('root'))

8.生命周期

8.1.旧版生命周期

React基础知识

class LifeCycler extends React.Component{
  constructor(props){
    super(props)
    console.log('constructor')
    this.state={
      num:0
    }
  }

  componentWillMount(){
    console.log('componentWillMount')
  }

  componentDidMount(){
    console.log('componentDidMount')
  }

  shouldComponentUpdate(){
    console.log('shouldComponenUpdate')
    return true
  }

  componentWillUpdate(){
    console.log('componentWillUpdate')
  }

  componentDidUpdate(){
    console.log('componentDidUpdate')
  }

  render(){
    console.log('render')

    const {num}=this.state
    return (
      <>
        <p>{num}</p>
        <button onClick={()=>this.setState({num:this.state.num+1})}>添加</button>
      </>
    )
  }

  add=()=>{

  }
}

ReactDOM.render(<LifeCycler/>,document.getElementById('root'))

第一次渲染页面时日志:

index.js:174 constructor
index.js:181 componentWillMount
index.js:202 render
index.js:185 componentDidMount

添加是日志:

index.js:189 shouldComponenUpdate
index.js:194 componentWillUpdate
index.js:202 render
index.js:198 componentDidUpdate

分析:

在页面初始化刷新时,首先会调用initialzation阶段,这个阶段主要是初始化state和props,接着组件将要挂载,渲染,组件挂载完成;

再点击添加时,首先调用了shouldComponentUpdate方法,此方法可以对React进行优化,接着将要更新,渲染,更新完成

shouldComponentUpdate:

状态更新时触发,如果返回值为false,后续的componentWillUpdate,render,componentDidUpdate将不会在调用,React中的PuerComponent就是通过这个方法做了一些优化

shouldComponentUpdate(nextProps,nextState){ //  代表的是下一次的属性 和 下一次的状态
  return nextState.num%2;//可以对数据进行一些处理
}

componentWillReceiveProps:

第一次渲染时不会执行,之后属性更新时才会执行,有一个参数newProps

componentWillUnMount:

组件卸载是调用

8.2.新生命周期

React基础知识

新的生命周期

去掉了:

  • componentWillMount,

  • componentWillUpdate,

  • componentWillReceiveProps,

新增了:

  • getDerivedStateFromProps

  • getSnapshotBeforeUpdate

class ParetLifeCycler extends React.Component{
  constructor(props){
    super();
    this.state = {number:0}
  }

  handleClick=()=>{
    this.setState({number:this.state.number+1});
  };
  render(){
    return (
      <>
        <p>{this.state.number}</p>
          <ChildLifeCycler number={this.state.number}/>
          <button onClick={this.handleClick}>+</button>
      </>
    )
  }
}

class ChildLifeCycler extends React.Component{
  constructor(props){
    super(props)
    console.log('constructor')
    this.state={
      num:0
    }
  }

  static getDerivedStateFromProps (nextProps, prevState){
    console.log('getDerivedStateFromProps')
    const {number} = nextProps;
    return {num:number+1}
  }
  componentDidMount(){
    console.log('componentDidMount')
  }
  shouldComponentUpdate(){
    console.log('shouldComponenUpdate')
    return true
  }

  componentDidUpdate(){
    console.log('componentDidUpdate')
  }

  getSnapshotBeforeUpdate (){
    console.log('getSnapshotBeforeUpdate')
    return null
  }

  render(){
    console.log('render')
    return (
      <>
        <p>{this.state.num}</p>
      </>
    )
  }
}

第一次渲染时:

index.js:242 constructor
index.js:249 getDerivedStateFromProps
index.js:271 render
index.js:254 componentDidMount

点击加号:

index.js:249 getDerivedStateFromProps
index.js:257 shouldComponenUpdate
index.js:271 render
index.js:266 getSnapshotBeforeUpdate
index.js:262 componentDidUpdate

getDerivedStateFromProps:

static getDerivedStateFromProps(props,state)是将传入的props映射到state上面

static getDerivedStateFromProps(nextProps, prevState) {
        const {number} = nextProps;
        // 当传入的type发生变化的时候,更新state
        if (number%2==0) {
            return { number:number*2};
        }else{
            return { number:number*3};
        }
        // 否则,对于state不进行任何操作
        return null;
    }

getSnapshotBeforeUpdate:

getSnapshotBeforeUpdate() 被调用于render之后,可以读取但无法使用DOM的时候。它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-05-10
  • 2021-12-14
  • 2021-07-13
  • 2021-10-13
  • 2022-12-23
  • 2021-09-21
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-11-16
  • 2022-12-23
相关资源
相似解决方案