梳理 React 知识笔记 从入门到放弃 !框架必知的知识点

本文深入探讨React框架,从简介到jsx语法,再到组件和生命周期的细节,解析React的核心特性,如虚拟DOM、函数式编程、组件化开发以及性能优化策略。通过学习,帮助开发者从入门到掌握React开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

React

一、React - 简介

​ React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框 架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套 东西很好用,就在2013年5月开源了。

二、前端三大框架

框架名出现时间所属一开始特色
Angular2009年谷歌指令系统、双向数据绑定
React2013年Facebook虚拟DOM、组件化
Vue2015年尤玉溪指令系统、双向数据绑定、虚拟DOM、组件化

2、react的特点

特点:

  1. 声明式设计 - React采用声明范式,可以轻松描述应用
  2. 高效 - React 通过对Dom的模拟(虚拟Dom),最大限度减少与Dom的交互
  3. 灵活 - React 可以与一直的库或框架很好的配合
  4. JSX - JSX 是 JavaScript 的语法扩展
  5. 组件 - 通过React构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中
  6. 单项响应的数据流 - React 实现了单项响应的数据流,从而减少了重复代码,这也是它为什么比传统的绑定更简单。

3、React 起步

3.1.全局安装 create-react-app 脚手架

$ npm i -g create-react-app

OR

$ npx create-react-app xxxx  //xxxx 是项目文件夹的名称

​ 3.2.创建项目文件夹**

$ create-react-app xxxx  //xxxx 是项目文件夹的名称

4、React 项目文件夹构成

  • react-stack -------------------项目文件夹
    • node_modules -------------------模块包
    • public -------------------静态资源目录
    • src --------------------项目文件
      • App.css
      • App.js
      • App.test.js
      • index.js
      • logo.svg
      • serviceWorker.js
      • setupTests.js
    • .gitignore
    • package.json
    • README.MD

5、视图层的开发模式与函数式编程

React 并不是完整的 MVC/MVVM 框架,它专注于提供清晰、简洁的 View(视图)层解决方案。

传统dom更新:

  • 真实页面对应一个Dom树。在传统页面的开发模式中,每次需要更新页面时,都需要手动操作Dom来进行更新

虚拟Dom:

  • Dom 操作非常昂贵,我们都知道在前端开发中,性能消耗最大的就是DOM操作,而且这部分代码会让整体项目的代码变得难以维护。React 把真实DOM树转换成JavaScript对象树,也就是Virtual DOM

函数式编程好处:

  1. 代码简洁,开发快速
  2. 接近自然语言,易于理解
  3. 更方便的代码管理
  4. 易于"并发编程“
  5. 代码的热升级

​ React把过去不断重复构建UI的过程抽象成了组件,且在给定参数的情况下约定渲染对应的UI界面。React能充分利用很多函数式方法去减少冗余代码。此外,由于它本身就是简单函数,所以易于测试。可以说,函数式编程才是React的精髓。

二、React - JSX语法

1、JSX 简介

​ JSX 将 HTML 语法直接加入到 JavaScript 代码中,再通过翻译器转换到纯 JavaScript 后由浏览器执行。在实际开发中,JSX 在产品打包阶段都已经编译成纯 JavaScript,不会带来任何副作用,反而会让代码更加直观并易于维护。 编译过程由Babel 的 JSX 编译器实现。

2、JSX 注意事项

  1. 组件首字母是大写 会被认为是自定义组件,首字母是小写,会被认为是 原生dom 节点
  2. 组件最外层需要被一个标签包裹,不能有兄弟节点
  3. return (加上小括号,可以回车)
  4. 组件可以嵌套
  5. 函数式写法class 写法 (无状态组件的编写方式 )
  6. 注释的写法 {这里面写注释} {//单行} {/多行/}
  7. 样式
    1. class ==> className , for ==> htmlFor(label)
    2. 行内样式(facebook 推荐),注意font-size 的写法
  8. 事件
    1. 箭头函数
    2. bind改变this指向
  9. ref
    1. 给标签设置ref=“username”
      1. 通过这个获取this.refs.username ,ref可以获取到应用的真实dom
    2. 给组件设置ref=“username”
      1. 通过这个获取this.refs.username ,ref可以获取到应用的真实组件对象

三、React - 组件

1、函数定义组件

function Title() {
  return <h1>Hello</h1>;
}

or

const Title = ()=> <h1>Hello</h1>;

2、类定义组件

class Child2 extends Component {
  render() {
    return <p>我是你家老二啊</p>
  }
}
  1. 不支持类写法, 函数式写法, React.creatClass

  2. es6普及, class(状态,属性,生命周期) ,函数式(不支持状态、生命周期,支持属性),

  3. 16.3 ==> class 生命周期写法升级

  4. 16.8 之后, 函数式组件=>支持状态,“生命周期", React Hooks ( Vue3.0 支持)

3、样式

import React, { Component } from 'react'
import './css/index.css' // webpack => css-loader style-loader
export default class App extends Component {
    render() {
        let myname ="kerwin"
        // style改造对象写法
        let styleobj = {
            background:"red",
            fontSize: "30px"
        }
        return (
            <div>
                <div style={styleobj}>11111-{10 + 20}</div>
                <div style={{background:"yellow"}}>22222-{10 > 20 ? 'aaa' : 'bbb'}</div>
                <div class="mybox">{myname + 'myname'}</div>
            </div>
        )
    }
}

16之前 className, 不能class

16之后 className class(警告)

4、定义状态

import React, { Component } from 'react'

export default class App extends Component {
//第一种写法:
    // constructor() {
    //     super()
    //     // react定义状态的方式
    //     this.state = {
    //         myname: "kerwin",
    //         myage: 100
    //     }
    //     this.a=100
    // }
    a= 100 //不是状态,
//第二种写法:
    state = {
        myname: "kerwin",
        myage: 100
    }//状态

    render() {
        return (
            <div>
                <div>hello -- {this.state.myname}--{this.state.myage}</div>
                <button onClick={this.handleClick}>click</button>
            </div>
        )
    }

    handleClick = () => {
        // this.state.myname = "xiaoming"  //不能直接修改
        this.setState({
            myname: "tiechui",
            myage:18
        })//用setState 间接修改
        // 虚拟dom创建 ==>对比老的虚拟节点 =>patch=>更新真实dom.
    }
}

5、修改state

state不可以直接修改

this.setState({
  count: this.state.count + 1
})
  • setState 并不保证是同步的 batchUpdate 批处理
  • 如果 setState 外部没有被异步处理程序包围,那么 setState 就是异步的
handleClick1 = ()=>{
        // setState 状态更新 是同步还是异步???
        this.setState({
            mytext:"22222222"
        },()=>{
            console.log("该回调函数,会等待状态更新完, 并且dom更新完,才会被调用",this.state.mytext)
        }) // 异步,创建虚拟dom,diff算法对比老的虚拟dom节点,patch ,最小代价更新真实dom
        console.log(this.state.mytext) 

}
or
<button
  onClick={() => {
    setTimeout(() => {
      this.setState({
        count: this.state.count + 10
      })
      this.setState({
        count: this.state.count + 1
      })
      this.setState({
        count: this.state.count + 15
      })
    }, 0)
  }}
    >1
  </button>
// 异步,所有执行语句累加
  • 如果 setState 外部被异步处理程序包围,那么 setState 就是同步的
handleAdd = ()=>{
  this.setState({
    count:this.state.count +1 
  })

  this.setState({
    count:this.state.count +1 
  })

  this.setState({
    count:this.state.count +10
  })

  //合并一个操作,只做一次虚拟dom 创建,只做一次diff对比
}// 执行最后一个

6、列表循环

{
   this.state.list.map((item,index)=>
     <li key={item}>
       {item}--{index}
     <button onClick={()=>{
        this.handleDelClick(index)
      }}>del</button>
  </li>
  )
}

7、条件渲染

{
this.state.list.length <= 0 ? 
  (<li>暂无代办事项</li>) 
   : 
  (
     this.state.list.map((item, index) => (
       <li key={index}>
          {item}---{index}
          <button onClick={() => this.delHandler(index)}>Del1</button>
       </li>
     )
  )
}

8、组件数据挂载的方式

1.属性(默认属性和属性验证)

  • 在组件上通过key=value 写属性,子组件通过this.props获取属性,这样组件的可复用性提高了

  • 注意在传参数时候,如果写成isShow="true"那么这是一个字符串,如果写成isShow={true}这个是布尔值

  • 默认属性/属性验证:

    子组件中

    //引入验证模块
    import propTypes from 'prop-types'
    //属性验证:
    static propTypes = {
      mytext: propTypes.string,
      myshow: propTypes.bool
    }
    
    //默认属性:
    static defaultProps = {
      mytext: 'Home',
      myshow: true
    }
    

9、组件通信

1.父组件------> 子组件

  • 父组件在子组件上设置自定义属性传值,设定自定义事件,
  • 子组件通过 this.props.xxxx接收 属性的传值

2.子组件------> 父组件

  • 子组件通过 this.props.onEvent(xxx) 通知父组件
  • 父组件执行 onEvent 事件处理函数

3.ref 通信

  • 子组件上加 ref=“mychild” 属性
  • 子组件中设定事件处理函数.handler1
  • 父组件用过 this.refs.mychild.handler1(xxxx)
  • 子组件执行 setState 修改自身的state状态

4.发布订阅模式

  • 先在组件全局定义一个对象 bus

    const bus = {
      list:[], //订阅者回调集合
      //订阅方法
      subscribe(callback){
        this.list.push(callback)
      },
      //发布方法
      dispatch(){
        this.list.forEach((back)=>{
          back()
        })
      }
    }
    
  • 订阅者,在componentDidMount 声明周期的时候 订阅方法调用

    componentDidMount(){
      console.log("dom渲染完的生命周期-订阅作用,axios"
      bus.subscribe((data)=>{
        console.log("app组件中定义的回调函数",data)
        this.setState({
          isCreated:!this.state.isCreated
        })
      })
    }//订阅,把回调传给bus,放入list
    
  • 发布者,事件触发后,调用 bus.dispatch()

    onClick={
    	()=>{
        bus.dispatch()
      } 
    }
    

5.content 状态树 跨级通信

  • 全局定义 GlobalContext

    import React from'react'
    const GlobalContext = React.createContext()
    
  • 根组件引入GlobalContext,并使用GlobalContext.Provider(辐射全局通信环境)

    export default class App extends Component {
      state = {
        isCreated: true,
        service: "打电话-付费",
      };
    
      render() {
        //多次被执行
        return (
          <GlobalContext.Provider
            value={{
              call: this.state.service,
              sms: "短信服务",
    
              changeCall: (data) => {
                console.log("改变套餐");
                this.setState({
                  service: "打电话-免费" + data,
                });
              },
    
              changeCreated: () => {
                this.setState({
                  isCreated: !this.state.isCreated,
                });
              },
            }}
          >
            <div
              style={{
                width: "510px",
                height: "500px",
                border: "1px solid black",
                display: "flex",
              }}
            >
              {this.state.isCreated ? <Sidebar /> : null}
              <Content></Content>
            </div>
          </GlobalContext.Provider>
        );
      }
    }
    
  • 任意组件引入GlobalContext并调用context,使用GlobalContext.Consumer(用户者)

    class Header extends Component {
      render() {
        return (
          <GlobalContext.Consumer>
            {(context) => (
              <div style={{ height: "100px", border: "1px solid #14c145" }}>
                <button
                  onClick={() => {
                    //发布
                    // context.call="11111111111"
                    context.changeCall("111111");
                    context.changeCreated();
                  }}
                >
                  切换
                </button>
                {context.sms}
              </div>
            )}
          </GlobalContext.Consumer>
        );
      }
    }
    

四、 React - 生命周期

1.初始化阶段

componentWillMount :render之前最后一次修改状态的机会

render : 只能访问this.props和 this.state,不允许修改状态和Dom 输出

componentDidMount :成功render并渲染完成真实Dom之后触发,可以修改DOM

2.运行中阶段

componentWillReceiveProps :父组件修改属性触发

shouldComponentUpdate :返回false会阻止render调用

componentWillUpdate :不能修改属性和状态

render : 只能访问this.props和 this.state,不允许修改状态和Dom 输出

componentDidUpdate : 可以修改DOM

3.销毁阶段

componentWillUnmount :在删除这个组件前进行清理操作

问题:

  1. componentWillMount ,在ssr中 这个方法将会被多次调用, 所以会重复触发多遍,同时在这里如果绑定事件, 将无法解绑,导致内存泄漏 , 变得不够安全高效逐步废弃。
  2. componentWillReceiveProps 外部组件多次频繁更新传入多次不同的 props,会导致不必要的异步请求。
  3. componetWillupdate, 更新前记录 DOM 状态, 可能会做一些处理,与componentDidUpdate相隔时间如果过长, 会导致 状态不太信。

解决:

  1. getDerivedStateFromProps 第一次的初始化组件以及后续的更新过程中(包括自身状态更新以及父传子) ,返回一个对象作为新的state,返回null则说明不需要在这里更新state

    static getDerivedStateFromProps(nextProps){
      if(nextProps.value!==undefined){
         return{
               current:nextProps.value
         }
      }
      return null
    }
    
  2. getSnapshotBeforeUpdate 取代了 componetWillUpdate ,触发时间为update发生的时候,在render之后dom渲染之前返回一个值,作为componentDidUpdate的第三个参数

4.react中性能优化的方案
  1. shouldComponentUpdate
    控制组件自身或者子组件是否需要更新,尤其在子组件非常多的情况下, 需要进行优化
  2. PureComponent
    1.PureComponent会帮你 比较新props 跟 旧的props, 新的state和老的state(值相等,或者对象含有相同的属性、且属性值相等 ),决定shouldcomponentUpdate 返回true 或者false, 从而决定要不要呼叫 render function。
    2.注意:如果你的 state 或 props 『永远都会变』,那 PureComponent 并不会比较快,因为 shallowEqual 也需要花时间。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值