React学习笔记

一、几个概念

库和框架
  • 库(library):小而巧,可以很方便的从一个库切换到另一个库,但是代码几乎不会改变。
  • 框架(framework):大而全,框架提供了一整套完整的解决方案,在项目中间想要切换框架是困难的
模块化和组件化
  • 模块化:是从代码的角度进行分析,把可复用的代码抽离为单个模块,便于项目的维护和开发
  • 组件化:从UI界面的角度进行分析,把可复用的UI元素,抽离为单独的组件

二、React的基础概念

1、虚拟DOM
  • DOM的本质:浏览器中的概念,用JS对象来表示页面上的元素,并提供了操作相应DOM对象的API
  • 虚拟DOM:是框架的概念,是程序员用JS对象来模拟页面上的DOM和DOM嵌套
  • 虚拟DOM的目的:为了实现页面中DOM元素的高效更新。
2、Diff 算法
  • tree diff: 新旧两棵DOM树,逐层对比的过程。当整个DOM逐层对比完毕,则所需要被按需更新的元素,必然能够找到
  • component diff :在进行tree diff的时候,每一层中,组件级别的对比。
    • 对比前后,组件类型相同,则认为此组件暂时不需要被更新
    • 对比前后,组件类型不同,则需要移除旧的组件,创建新的组件,并追加到页面上。
  • element diff:在进行组件对比的时候,如果两组件类型相同,则需要进行元素级别的对比。

三、使用webpack4.x搭建项目

  1. npm init -y 初始化
  2. 创建src源代码目录和dist目录
  3. 安装:npm i webpack -D npm i webpack-cli -D
  4. 在webpack.config.js中配置mode
      module.exports={
           mode:‘development’,//development 开发环境,
          //在webpack 4.x中有一个很大的特性 约定大于配置
       }
    
  5. 约定大于配置,打包入口路径:在src下的index.js,出口文件:dist下的main.js
  6. 配置实时编译 npm i webpack-dev-server -D后在package.json的scripts下"dev":"webpack-dev-server"--->npm run dev--->引入的js文件在根目录
  7. 配置html-webpack-plugin

四、使用React渲染最基本的虚拟DOM到页面上

1、下载、引入
  • 下载 npm i react react-dom
  • 在index.js中引入:import React from ‘react’ import ReactDom from 'react-dom'
2、创建虚拟的dom元素
  • const myh1 = React.createElement(‘h1’,null,‘这是一个h1’)
    • 参数1:创建的元素的类型,字符串,表示元素的名称
    • 参数2:一个对象或者null,表示当前dom元素的属性
    • 参数3:子节点(包括 其他 虚拟DOM 或者文本的子节点)
    • 参数n:其他子节点
3、使用ReactDom把虚拟DOM渲染到页面上
  • ReactDom.render(myh1,document.getElementById("app"))
    • 参数1:要渲染的虚拟DOM元素
    • 参数2:指定页面上的一个容器
4、例子
   import React from 'react'
   import ReactDom from 'react-dom'
   var myDiv = React.createElement('h1',null,'这是react');
   ReactDom.render(myDiv,document.getElementById('box'))

五、JSX介绍和使用

  • 在JS中默认不能写入html标记,否则会打包失败,可以使用babel来转换这些js标签,在js中混入类似于html的语法叫做JSX,符合xml规范
  • JSX语法的本质:在运行的时候被转换成React.createElement形式来执行
1、启用JSX
  • 安装babel插件
    • npm i babel-core babel-loader babel-plugin-transform-runtime -D
    • npm i babel-preset-env babel-preset-stage-0 -D
  • 安装能够识别转换JSX语法的包
    • npm i babel-preset-react -D
  • 在webpack.config.js中添加babel-loader
    module://所有第三方 模块的配置规则
    {
       rules:[//第三方匹配规则
           { test:/\.js|jsx$/,use:'babel-loader' , exclude:/mode_modules/}
        ]
     }
    
  • 添加.babelrc配置文件
    { 
       "presets" : ["env","stage-0","react"],
       "plugins" : ["transform-runtime"]
    }
    
2、在JSX中书写JS代码注意点
  • 变量使用{a}插入
  • 标签中的属性值:title={}
  • 在JSX中,写注释{//}(需要换行)、{/* 这是注释 */},
  • 为JSX中得元素添加class类名需要使用className来替代class,htmlFor替代for
  • 在JSX语法中,标签必须成对出现,单标签则必须自闭和。
  • 在JSX创建DOM的时候,所有的节点,必须有唯一的根元素进行包裹
  • 在JSX中不能为style设置字符串的值,应该写style = {{color:‘red’}},行内样式,如果是字符串类型就需要引号包裹。
let message = '这是js中的参数'
let nameStr = ['张三','李四','王五','赵六']
let nameArr = []
  nameStr.forEach((item)=>{
        let nameItem = <h5 key={item}>{item }</h5>
        nameArr.push(nameItem)
  })
{
  //什么时候使用{}:当在JSX控制的区域内,写JS表达式就需要
}
ReactDom.render(
 <div className = "main"> { message }
     <hr/>
    {nameArr}
    <hr/>
    {nameStr.map( item => <h5 key={item}>{item}</h5> ) }//方法二
 </div>
 ,document.getElementById('app'))

六、组件

1、使用构造函数来创建组件:
  • 创建组件

    // 组件名称的首字母需要大写
      function Hello (props) {
         //在构造函数中接收外界传入的参数,传入的prop是只读的
           console.log( props )//{ name : '张三',  age : 14}
          //如果return null表示组件是空的什么都不渲染
         //组件必须ruturn,必须返回一个合法的 JSX 虚拟DOM元素
           return <div>这是Hello组件</div>  
      }
     <hello name='张三'  age = 14></hello>
     //还可以使用解构赋值来传递对象
      var dog={
         name:‘旺财’,
         age:12
      }
     <hello {...dog}></hello>
    
  • 分离组件

      //文件名:Hello.jsx
       import React from 'react'
            export default function Hello(props){
            return <div>{props.name}</div>
         }
     //在index.js中导入使用,默认不做单独配置的话,不能省略.jsx后缀
     import Hello from '路径/Hello.jsx'
    
    • 使用 Person.defaultProps = { sex:'男' } 设置传递参数的默认值
    • 使用 Person.propTypes = { name:PropTypes.string.isRequired }设置属性的类型和必要性
    • 配置,省略后缀名,在webpack.config.js中添加
      resolve:{ 
          extension:['.js' , '.jsx' , '.jsx' ],//表示这几个文件名后缀可以省略
          //配置webpack设置项目根目录
          alias:{//表示别名
             '@':path.join(__dirname,'./src')//这样@就表示项目根目录中src这一层路径
          }
      }
      
2、基于关键字class创建组件
  • 静态属性和实例属性
    • 静态属性用static修饰,用类名访问
  • 静态方法和实例方法
  • 在class{}中只能写构造器、静态方法、静态属性、实例方法
  • class关键词内部,还是用原来的配方实现,所以class称为语法糖
  • 继承时,子类constructor(){需要super() }
     class Movie extends React.Component{//必须继承Component
           render(){//必须有render函数
               return <div> 我是一个组件</div>//必须返回合法的 JSX虚拟DOM结构
            }
         }
      ReactDom.render(<div>
               <Movie></Movie>
               </div>
            , document.getElementById('app'))
    
  • 使用this.props.参数名获取参数
4、两种创建组件方式的区别
  • 使用class关键字创建的组件,有自己的私有数据和生命周期数;用function创建的组件,只有props。
  • 构造函数创建出来的组件叫做“无状态组件”,用class创建的组件“有状态组件”
  • 两种方式之间的区别是:有无state属性和有无生命周期
5、组件中propsstate/data之间的区别
  • props中的数据都是外界传递过来的;
  • state/data中的数据,都是组件私有的(通过Ajax获取回来的数据,一般都是私有数据)
  • props中的数据是只读的,不能重新赋值,state/data中数据可读可写
6、在组件内使用内联样式style
  • 在JSX中如果想写行内样式,不能为style设置字符串的值,而是应该写成style={ { color:‘red’ } }
  • 在行内样式中,如果是数值类型的样式则不用引号包裹,如果是字符串类型的样式值,必须用引号包裹。
  • 可以封装成一个样式对象通过import 引入
  • 引入css,需要配置。直接导入css样式表,默认是在全局上整个项目都生效。
7、为css启用modules
  • 在webpack.config.js中配置css时
  • rules:[ { test: /\.css$/, use:['style-loader','css-loader?modules']} ], //modules为普通的css启用模块化
    • 启用模块化后,不会在全局生效
  • css模块化,只针对 类选择器 和id选择器生效,不会将标签选择器模块化
  • 使用localIdentName自定义生成类名格式,可选参数有:
    • [path] 表示样式表 相对于项目根目录 所在的路径
    • [name] 表示样式表 文件名称
    • [local] 表示样式表 类名定义名称
    • [hash:length] 表示32位的hash值
    • 例子:
    //在webpack.config.js中
    rules:[  { 
      test: /\.css$/, use:['style-loader','css-loader?modules&localIdentName=[path][name]']
    } ]
    
    // 在cmtlist.jsx中
    import cmtStyle from ‘@/css/cmtlist.style’
    <h1 id={cmtStyle.title}>标题</h1>
    
  • 被:local()包裹起来的类名,会被模块化,默认所有的类名和id都被模块化。
  • :global()包裹起来的类名,不会被模块化,而是全局生效
七、在项目中启用模块化并同时使用bootstrap
  • 打包处理 字体文件的loader:{test:/\.ttf|woff|woff2|eot|svg$/,use:'url-loader'}
  • 如果在引用某个包时,这个包被安装到了node_modules目录中,则可以省略node_modules这一层目录,直街以包名开始引入自己的 模块或样式表
  • 自己规定:
    1. 把自己的样式表,定义为.scss文件或 .less文件。
    2. 第三方的 样式表 还是以.css结尾
    3. 我们只需要为自己的.scss文件或 .less文件,启用模块化
  • 安装能够解析scss文件的loader: 运行npm i sass-loader node-sass -D
     //css文件无需模块化
     { test: /\.css$/, use:[ 'style-loader','css-loader','sass-loader']},
     //scss启用模块化 
     { test: /\.scss$/, use:[ 'style-loader','css-loader?modules','sass-loader']}  
    

八、React中绑定事件

  • onClick = { function }

  • 在方法中修改state中的值,使用this.setState({msg:})

    • setState的注意点:
      • setState只会把对应的state状态更新,而不会覆盖其他的state状态
      • setState方法是异步的,调用完需要马上用到新值需要使用 this.setState({},callback)
  • 注释://#region 开始注释 //#endregion

  • 获取文本框的值

    • e.target.value
    • this.refs.txt.value
      class BtnEvent extends React.Component{
        constructor(){
            super()
            this.state = { msg:'这是测试事件的组件'  }
        }
        render(){
            return <div>
                <button onClick={()=> this.setDate('🐖','🐕')}>改变值</button>
                <p>{this.state.msg}</p>
                {/* 为文本框绑定value值以后,要么同时提供一个readOnly,要么提供一个onChange处理函数**/}
                <input type="text" value={this.state.msg} style={{width:'300px'}} onChange={(e)=>this.changeInput(e)} ref='txt'/>
                </div>
          }
        setDate=(arg1,arg2)=>{
           this.setState({ msg: arg1+arg2 },()=>{ 
                      console.log(this.state.msg) }) 
          }
        changeInput = (e)=>{
            //获取文本框的值有两种方法,
            this.setState({msg:e.target.value})//一:通过时间参数e获取
            console.log(this.refs.txt.value) //二:this.refs.txt..value
        }
    } 
    

九、组件的生命周期

  • 生命周期的概念:每个组件的实例从创建、运行到销毁,在这过程中,会促发一些事件,这些事件就叫做组件的生命周期函数
  • 组件的三个生命周期状态:
    • Mount:插入真实的DOM
    • Update:被重新渲染
    • Unmount:被移出真实的DOM
  • 组件的创建阶段:只执行一次
    • componentWillMount():将要插入回调
    • render():用域插入虚拟DOM回调
    • componentDidMount():已经插入回调
  • 组件的运行阶段、更新
    • componentWillReceiveProps():
    • shouldComponentUpdate()
    • componentWillUpdate():将要更新
    • render():更新(重新渲染)
    • componentDidUpdate():已经更新
  • 组件的销毁阶段:只执行一次
    • componentWillUnmount():组件将要被移除
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容