美文网首页
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