美文网首页
React学习笔记

React学习笔记

作者: DoEmpty | 来源:发表于2018-09-06 22:59 被阅读13次

    1).React核心概念

    • 虚拟DOM(Virtual Document Object Model)
      假如存在如下的Html结构,在js中可以获取到对应的DOM对象,因为JS中的DOM映射机制,可以通过操作js中的DOM对象来完成对页面的重排或重绘。但是DOM的操作成本是比较高的,所以引入虚拟DOM的概念。`所谓虚拟DOM就是与真实的DOM对象一一对应的普通JS对象
    <div id="div1" style="background:red">
      Hello 简书!
      <p id="p1">可以在这里做笔记哦</p>
    </div>
    
    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的容器
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <title>home page</title>
      </head>
      <body>
          <!-- React容器   虚拟DOM在这里渲染 -->
          <div id="app"></div>
      </body>
      <!-- 切记:这里不可以把main.js在head中引用,因为这时这是body还没有加载,但是在 
      js中react已经用到了app容器 -->
      <script src="/main.js"></script>
      </html>
      
    • 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') //<h1 id='myh1' title='this is a h1'>this is a h1 element</h1> 
      
      //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 <div>{{props.name}}</div>
      }
      ReactDOM.render(<div>
        <Hello name='kerry'></Hello>
      </div>,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 <div>{this.props.name}</div>
        }
      }
      
    • 3.异同
      • 使用class创建的组件,有自己的私有数据state和生命周期函数,叫做“有状态组件
      • function创建的组件,只有props,没有自己的私有数据和生命周期函数,叫做“无状态组件
      • 有状态组件与无状态组件的本质区别是有无state

    5).React中的元素样式

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

    • 1.内联样式

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

      但是,使用上述方式定义的样式是全局的,一次引用,每个组件都可以使用,容易造成样式混乱,因为样式表不同于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://img.haomeiwen.com/i3566275/ cc80053689b64f1b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

      • 3.3. 为需要的元素添加className或id(css-loader模块化只是针对class或id选择器生 效),<li className={stylesObj.itemli}>
      • 3.4. 非模块化与模块化的样式表异同在于
        *非模块化的样式表编译后,样式表解析在index.html的<style>标签中,类名同于样式表的类名
        *模块化样式表编译后,样式表同样解析在index.html的<style>标签中,不同的是,类名是被混淆的而非样式表中原始类名
        ![模块化样式表编译后](https://img.haomeiwen.com/i3566275/ 4c40688f04a446a9.png?imageMogr2/auto-orient/strip%7CimageView2/3/w/500)
        ![非模块化样式表编译后](https://img.haomeiwen.com/i3566275/ 58ba9610b50df1aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/500)
    • 4.自定义样式表模块化名称
      开启css-loader的模块化会对样式表中的类名进行混淆,如果不想要混淆,而是通过一定规则定义的怎么做呢?

      使用css-loader的localIdentName参数自定义生成的类名格式,可选参数有
      - [path]表示对样式表编译后生成的类名具有相对于项目根目录所在的路径
      - [name]表示生成的类名具有样式表文件名
      - [local]表示生成的类名具有样式表中定义的原始类名
      - [hash:length]表示生成的类名具有length长的的hash值

      使用localIdentName参数自定义的stylesObj
      如图所示,四段分别对应四个可选参数,如此便可以看到有意义的className
       {test:/\.css$/,use:['style-loader','css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]']}
      

    相关文章

      网友评论

          本文标题:React学习笔记

          本文链接:https://www.haomeiwen.com/subject/lgnnmftx.html