React学习笔记

1).React核心概念

  • 虚拟DOM(Virtual Document Object Model)
    假如存在如下的Html结构,在js中可以获取到对应的DOM对象,因为JS中的DOM映射机制,可以通过操作js中的DOM对象来完成对页面的重排或重绘。但是DOM的操作成本是比较高的,所以引入虚拟DOM的概念。`所谓虚拟DOM就是与真实的DOM对象一一对应的普通JS对象
Hello !

可以在这里做笔记哦

var vDom={
    id:"div1",
    style:"background:red",
    children:[
        "Hello !",
        {
            id:"p1",
            children:["可以在这里做笔记哦"]
        }
   ]
}
  • Diff算法(分以下三步)
    • tree diff:新旧两颗DOM树,逐层对比的过程就是Tree Diff;当整颗DOM树对比完毕,则可以保证所有需要更新的元素必然可以找到。
    • component diff:对于组件化开发,DOM树中的每个层级都是各种的组建,在进行Tree Diff的时候,每一层中,组件级别的对比,叫做Component Diff

    1.如果对比前后,组建的类型相同,则暂时认为此组件不需要被更新
    2.如果对比前后,组建的类型不同,则需要移除旧的组建,创建新组建并追加到页面上。

    • element diff:在进行组建对比的时候,如果两个组建类型相同,则需要进行元素级别的对比,叫做Element Diff

2).使用webpack4.x构建项目

  • 1.初始化项目,创建一个目录,在根目录下运行npm init。(npm init -y快速初始化项目)
  • 2.在项目根目录创建src源代码目录和dist产品目录
  • 3.在src目录下创建一个index.html以及index.js入口文件(这里填写自己的js代码)
  • 4.安装webpack,npm i webpack --save-dev(在当前目录下安装),webpack默认只能打包处理.js文件,其他格式的需要配置第三方loader规则,webpack4.x具有约定大于配置的概念:目的是为了尽量减少配置文件的体积
    • 默认约定了打包的入口文件是src/index.js
    • 打包的输出文件时dist/main.js
  • 5.安装webpack-cli,在package.json的script添加编译命令"build":"webpack"
  • 6.在根目录下创建webpack.config.js文件,在webpack.config.js中指定mode
    module.exports = {
     mode: 'production' //or production
    };
    
  • 5.设置打包命令,在根目录package.jsonscripts节点添加"build": "webpack",就可以终端运行npm run build来打包代码了,可以看到在dist下有一个main.js的输出文件
  • 6.运行npm i webpack-dev-server --save-dev安装webpack-dev-server
  • 7.设置编译发布命令,在根目录package.jsonscripts节点添加"dev": "webpack-dev-server",就可以通过执行npm run dev命令来将网站托管在localhost的端口上,并且代码修改可以及时反映在浏览器中而不用执行编译脚本

    "dev": "webpack-dev-server --open chrome --host 127.0.0.1 --port 3000 --hot"
    //编译发布 在浏览器中打开 设置host 设置port 热替换

  • 8.添加js引用,在src/index.html添加对/main.js的引用

    webpack-dev-server打包好的main.js是托管在内存中的(避免频繁ctrl+s频繁编译),所以在磁盘的根目录中看不到,但是可以认为,在项目根目录下有一个看不见的main.js

3).在项目中使用React

  • 1.安装React包,运行npm i react react-dom --save(--save or -S在开发/生产都要用的的安装包)
    • react:专门用于创建组件和虚拟DOM的,同时维护组件的生命周期
    • react-dom:专门进行DOM操作的,主要的应用场景,就是ReactDOM.render()
  • 2.在index.html页面中,创建react渲染虚拟DOM的容器
    
    
    
        
        
        
        home page
    
    
        
        
  • 3.在入口文件index.js中导入包、创建虚拟DOM元素、使用ReactDOM将虚拟DOM元素渲染到页面容器中
    //1.引入React包,以下两个react包导入的时候必须用以下两个名字接收
    import React from 'react'  //创建组件、虚拟DOM元素、生命周期
    import ReactDOM from 'react-dom'  //在页面渲染创建好的组件和虚拟DOM
    
    //2.创建虚拟DOM元素
    //param1:字符串 创建的元素名称  
    //param2:对象或null 表示当前这个DOM元素的属性  
    //param…:子节点  (其他若干参数)
    const myh1 = React.createElement('h1',{id:'myh1',title:'this is a h1'},'this is a h1 
    element') //

    this is a h1 element

    //3.使用ReactDOM把虚拟DOM渲染到页面上 //param1:要渲染的虚拟DOM元素 //param2:指定一个DOM元素,作为渲染虚拟DOM的容器 ReactDOM.render(myh1,document.getElementById('app'))
  • 4.启用JSX语法(符合XML规范的js语法,类似与HTML)
    • 安装babel插件:
      npm i babel-core babel-loader babel-plugin-transform-runtime --save-dev
      npm i babel-preset-env babel-preset-stage-0 --save-dev
    • 安装能够识别JSX语法的包:npm i babel-preset-react -D
    • 在项目根目录添加.babelrc配置文件,该文件为JSON格式
      {
          "presets":["env","stage-0","react"],
          "plugins":["transform-runtime"]
      }
      
    • 在webpack配置文件中,配置babel-loader对jsx语法的解析规则
      //webpack.config.js
      module.exports = {
        mode: 'development',
        module:{//配置loader 所有第三方模块的配置规则
            rules:[
                {test:/\.js|jsx$/,use:'babel-loader',exclude:/node_modules/}
            ]
        }
      };
      

      在JSX语法区域内,如果需要写JS表达式,则需要把JS代码写在{}中

4).React组件的两种创建方式

  • 1.构造函数方式
    • 组件如果需要接收外界的数据,需要在构造函数列表中使用props来接收,props就相当于DOM元素的属性一般赋值。
    • 在一个组件中,必须要一个返回值,这个返回值是一个合法的JSX虚拟DOM元素,如果return null,则表示此组件是空的.
    • props是只读的,props需要用形参接收。
    • 组件的首字母必须大写
    function Hell(props){
        return 
    {{props.name}}
    } ReactDOM.render(
    ,document.getElementById('app'))
  • 2.Class方式
    • 使用class定义组件,必须让组件继承自React.Component
    • 组件内部必须有render函数,render函数必须返回合法的JSX虚拟DOM结构
    • 最基本的组件结构:
    • props是只读的,在class中可以通过this.props使用
    • 有自己的私有数据state,class内部自身维护的可读写的数据,不通于props是通过外界传递而来
    class 组件名称 extends React.Component{
      constructor(){
        super();
        this.state={}
      }
      render(){
        return 
    {this.props.name}
    } }
  • 3.异同
    • 使用class创建的组件,有自己的私有数据state和生命周期函数,叫做“有状态组件
    • function创建的组件,只有props,没有自己的私有数据和生命周期函数,叫做“无状态组件
    • 有状态组件与无状态组件的本质区别是有无state

5).React中的元素样式

React中的元素样式属性名也是style,但是不接收字符串,而是以双层大括号包裹,外层大括号表示在JSX中的JS代码,内层大括号表示一个对象。且样式属性对象的key必须是小写字母开头的驼峰写法

  • 1.内联样式

    function ItemComp(props){
        //1.直接将样式写在元素内
        // return 
  • // id:{props.id} // code:{props.code} //
  • ; //2.将样式封装成对象,也可以抽出到一个单独的js文件中然后import const styles={ li:{color:'red',txetAlign:'center',width:'60%'}, spanId:{fontSize:'14px'}, spanCode:{float:'right',display:'inline-block'} } return
  • id:{props.id} code:{props.code}
  • ; }
  • 2.外联样式(样式表)

    • 2.1 安装样式相关的包,运行npm i style-loader css-loader -D
    • 2.2 webpack.config.js的module的rules节点配置cssloader
    let path=require('path')
    module.exports = {
      mode: 'development',
      module:{//配置loader 所有第三方模块的配置规则
          rules:[
              {test:/\.js|jsx$/,use:'babel-loader',exclude:/node_modules/},//exclude,排除项
              {test:/\.css$/,use:['style-loader','css-loader']}//配置打包处理css样式表的第三方loader,webpack的loader匹配规则是从右到左
          ]
      },
      resolve:{
          extensions:['.js','.json','.css'],//表示在引用这几种后缀名的文件时,可以省略不写后缀名
          alias: {//声明别名,编译的时候会按照这里的规则将别名替换掉
              '@': path.join(__dirname,'./src')
          }
      }
    };
    
    • 2.3 新建一个样式表,按照css语法书写样式
    .itemli{
      color:red;
      text-align:center;
      width:60%
    }
    
    • 2.4 在需要使用样式的组件中导入样式表文件
    import stylesObj from './../css/itemcomp.css';
    
    • 2.5 在需要应用样式的元素中添加className属性
    return 
  • 列表项
  • ;

    但是,使用上述方式定义的样式是全局的,一次引用,每个组件都可以使用,容易造成样式混乱,因为样式表不同于JS没有作用域的概念,那么怎么解决这个问题呢?

  • 3.模块化的样式表

    • 3.1. 为css-loader配置参数以支持普通的css样式表启用模块化
    //css-loader可以通过?追加参数
    //modules表示为普通样式表启用模块化
    {test:/\.css$/,use:['style-loader','css-loader?modules']}//配置打包处理css样式表的第三      方loader,webpack的loader匹配规则是从右到左
    
    • 3.2. 启用模块化样式表后,import的样式表不同于未启用模块化的空对象,是具有值 的
    import stylesObj from './../css/itemcomp.css';
    console.log(stylesObj);
    

    ![image.png](https://upload-images.jianshu.io/upload_images/3566275- cc80053689b64f1b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

    • 3.3. 为需要的元素添加className或id(css-loader模块化只是针对class或id选择器生 效),
    • 3.4. 非模块化与模块化的样式表异同在于
      *非模块化的样式表编译后,样式表解析在index.html的