React的起源和发展
重点:
-
react是第一个使用虚拟DOM前端框架
-
react适合做大型企业级项目
-
轻量级的视图层库 —React不是一个完整的MVC框架,最多可以认为是MVC中的V(View),甚至React并不非常认可MVC开发模式
-
React最为重要的一个部分就是: 组件
-
React高性能的体现:虚拟DOM
-
虚拟DOM(待复习) https://segmentfault.com/a/1190000016647776?utm_source=tag-newest
-
在Web开发中我们总需要将变化的数据实时反应到UI上,这时就需要对DOM进行操作。而复杂或频繁的DOM操作通常是性能瓶颈产生的原因(如何进行高性能的复杂DOM操作通常是衡量一个前端开发人员技能的重要指标)。
React为此引入了虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别【 patch 补丁对象 】,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。而且React能够批处理虚拟DOM的刷新,在一个事件循环(Event Loop)内的两次数据变化会被合并,例如你连续的先将节点内容从A-B,B-A,React会认为A变成B,然后又从B变成A UI不发生任何变化,而如果通过手动控制,这种逻辑通常是极其复杂的。( https://www.cnblogs.com/wind-lanyan/p/9061684.html )
尽管每一次都需要构造完整的虚拟DOM树,但是因为虚拟DOM是内存数据,性能是极高的,因而对实际DOM进行操作的仅仅是Diff算法,因而能达到提高性能的目的。这样,在保证性能的同时,开发者将不再需要关注某个数据的变化如何更新到一个或多个具体的DOM元素,而只需要关心在任意一个数据状态下,整个界面是如何Render的。
-
-
算法:React Fiber
- React Fiber的方法其实很简单——分片。把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。
-
React的特点和优势
- 虚拟DOM
- 组件系统
- 单向数据流
- JSX 语法:jsx :在js中引入html结构
-
npx:在5.2版本上才可以用
-
yarn:保证第三方依赖版本不变
-
jsx里面的注释:快捷键: ctrl + /
构建一个脚手架
说明
React中使用的是ES6规范
-
React是不能直接在浏览器中运行的,必须借助工具才能运行React程序
- 因为React是jsx,它必须经过webpack编译为js才能运行
-
React的快速构建工具
- CRA [ react官方推荐的 ]
- Dva
- Umi
-
通过CRA来构建项目
- 构建流程
- 安装CRA [ create-react-app ]
- 全局安装
yarn add create-react-app global
cnpm i create-react-app -g
- 临时使用 [ npx ]
npx create-react-app 项目名称
- 全局安装
- 启动项目
$ yarn start
- 打包项目
$ yarn build
- 配置文件抽离
$ yarn eject
这个动作不可逆【 不能返回 】
-
React元素
- React元素就是一个普通的jsx
-
函数式组件
-
代码思路:
index.js /* * 项目入口文件 - 整个项目的灵魂 */ import React from 'react' // React的顶级库,它里面有很多的React的api,并且我们要向使用jsx,那么必须引入它,它是对jsx的支持 import ReactDOM from 'react-dom' // 它的作用就是将React组件编译为DOM结构,然后插入到浏览器网页中 // React元素 - 普通的jsx - jsx就是虚拟DOM对象模型 // ReactDOM.render( 元素/组件, 一个已有的容器 ) ReactDOM.render( <h3> React元素 </h3>, document.querySelector('#root') )
// const ele = <h3> React元素 </h3> //写成一个函数,可以传参 const App = ( props ) => { //这样使内容更加灵活 return <h3> { props.info } </h3> } ReactDOM.render( App({ info: 'hello react' }), document.querySelector('#root') )
最终版: //函数式组件 const App = ( props ) => { //这样使内容更加灵活 //props参数会接收App组件上的属性 return <h3> { props.info } </h3> } ReactDOM.render( <App info = 'hello react'/>,//改成标签化形式,更符合组件思维 document.querySelector('#root') )
-
代码二:函数式组件中的this是undefined,不要输出
import React,{Component,Fragment} from 'react' const FunComp = props =>{ // console.log( this ) //undefined return ( <Fragment> <p> name: { props.name } </p> </Fragment> ) } export default FunComp
-
-
在React中,函数也可以是一个组件,但是记住了,这个函数必须返回一个jsx结构
-
函数式组件有一个参数 props , 这个props可以接收绑定在函数式组件身上的属性
-
好处:
- js的最大特点: 函数式编程
- react符合函数式编程思想的
- 函数的好处: 复用性高、独立作用域
-
-
React第二类组件: 类组件
-
代码:
index.js import React from 'react' import ReactDOM from 'react-dom' import App from './App' ReactDOM.render(<App/>,document.querySelector('#root'))
App.js /* 类组件 App打造 */ import React,{ Component,Fragment } from 'react' class App extends Component{ render (){ return ( //jsx结构-要有为一根元素, <Fragment>可以充当唯一根元素并且不会在页面中展示 <Fragment> <h3>类组件</h3> </Fragment> ) } } export default App
-
代码二:
import React from 'react' import ReactDOM from 'react-dom' import App from './App' ReactDOM.render( <App name = 'gj'/>,//组件上绑定了一个属性 document.querySelector('#root') )
import React,{ Component,Fragment } from 'react' class App extends Component{ render (){ console.log( this ) return ( //jsx结构-要有为一根元素, <Fragment>可以充当唯一根元素并且不会在页面中展示 <Fragment> <h3>类组件</h3> <p> name:{ this.props.name } </p> //通过this.props...来访问 </Fragment> ) } } export default App
-
-
-
辅助工具
- vs code 插件
- Simple React Snippets
- ES7 React/Redux/GraphQL/React-Native snippets
- React-Native/React/Redux snippets for es6/es7
- chrome浏览器
- React developer tools
- vs code 插件
-
React目录
组件的组合与嵌套
嵌套
-
组件嵌套的方式就是将子组件写入到父组件的模板中去,且react没有Vue中的内容分发机制(slot),所以我们在一个组件的模板中只能看到父子关系
-
代码:在父组件中以标签化的形式引入子组件
Father import React,{ Component,Fragment } from 'react' import Son from './Son'; class Father extends Component{ render (){ return ( <Fragment> <Son></Son> </Fragment> ) } } export default Father
Son import React,{Component,Fragment} from 'react' class Son extends Component{ render(){ return ( <Fragment> <h4> 这是Son组件 </h4> </Fragment> ) } } export default Son
组合
-
类似于Vue的插槽:{this.props.children}–组件内容里也可以写组件
-
代码示例
-
Father import React,{ Component,Fragment } from 'react' import Son from './Son'; class Father extends Component{ render (){ return ( <Fragment> <Son>10.15</Son> </Fragment> ) } } export default Father
-
Son import React,{Component,Fragment} from 'react' class Son extends Component{ render(){ return ( <Fragment> <h4> 这是Son组件 </h4> { this.props.children } </Fragment> ) } } export default Son
jsx原理(了解)
javascript语法扩展 js+html
React中通过React.createElement() 将jsx编译为js对象模型
jsx可以在js中写html结构
- React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接在 JavaScript 代码里面编写类似 HTML 标签结构的语法,这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。
- 所谓的 JSX 其实就是 JavaScript 对象,所以使用 React 和 JSX 的时候一定要经过编译的过程:
JSX —使用react构造组件,babel进行编译—> JavaScript对象 —
ReactDOM.render()
—>DOM元素 —>插入页面
组件中的DOM样式(四种)
-
行内样式
-
想给虚拟dom添加行内样式,需要使用表达式传入样式对象的方式来实现:
-
代码:
-
import React,{ Component,Fragment} from 'react' export default class CompOne extends Component{ render(){ return ( <Fragment> <h3> React样式添加--行内样式 </h3> <p style = {{width:'100px',height:'100px',background: 'red'}}></p> </Fragment> ) } }
-
扩展:
-
import React,{ Component,Fragment} from 'react' export default class CompOne extends Component{ styled = { text:{width:'100px',height:'100px',background:'green'} } render(){ const styles = { text: { width:'100px',height:'100px',background:'blue'} } return ( <Fragment> <h3> React样式添加--行内样式 </h3> <p style = {{width:'100px',height:'100px',background: 'red'}}></p> <p style = {styles.text} ></p> <p style = {this.styled.text} ></p> </Fragment> ) } }
-
-
使用class
-
class
需要写成className
(因为毕竟是在写类js代码,会收到js规则的限制,而class
是关键字) -
代码:
-
import React,{ Component,Fragment} from 'react' //用模块化引入css文件 import './CompTwo.css' export default class CompTwo extends Component{ render(){ return ( <Fragment> <h3> React样式添加--类名的添加 </h3> <p className = "size bg"> </p> </Fragment> ) } }
-
.size{ width: 100px; height: 100px; } .bg{ background:yellow }
-
扩展:sass less
- React项目中引入sass
- 需要安装两个包 node-sass sass-loader
- less如何引入
- 安装sass-loader时出现这样的问题:warning package.json: “dependencies” has dependency “sass-loader” with range “7.2.0” that collides with a dependency in “devDependencies” of the same name with version “^7.2.0”
- React项目中引入sass
-
代码:sass( 复习)
-
-
不同的条件添加不同的样式 —练习
-
首先要先安装一个包:yarn add classname/cnpm i classname -D
-
用法要在npm.js网站找文档学习—学会利用文档来学习
-
代码示例:
-
import React,{ Component,Fragment} from 'react' import './CompThird.css' import classname from 'classname' class CompThird extends Component{ render(){ return( <Fragment> <h3> React样式添加 - 不同的条件添加不同的样式</h3> <p className = {classname({ size:true, success: true, fail:false })} ></p> </Fragment> ) } } export default CompThird
-
.size{ width: 100px; height: 100px; } .success{ background: greenyellow } .fail{ background: red }
-
-
css-in-js ( 在js中写css )—练习
-
安装:cnpm i styled-components -D
-
可以应用npm.js中文档学习 styled-components
-
应用一
-
import React,{Component,Fragment} from 'react' import styled from 'styled-components' const Container = styled.div` width: 200px; height: 200px; border: 1px dashed black; p{ width:50px; height:50px; background:#ccc } ` const CompFour = props =>{ return( <Fragment> <h3> React样式添加 - 样式组件</h3> <Container> <p> 头部 </p> </Container> </Fragment> ) } export default CompFour
-
应用二:
-
import React,{Component,Fragment} from 'react' import styled from 'styled-components' const Container = styled.div` width: 200px; height: 200px; border: 1px dashed black; header{ width:50px; height:50px; background:${props => props.flag && 'red' || 'blue'} i{ display:block; width:20px; height:20px; background:${props => props.color}; } } ` const CompFour = props =>{ return( <Fragment> <h3> React样式添加 - 样式组件</h3> <Container color = 'green' flag = {true}> <header> 头部 <i></i></header> </Container> </Fragment> ) } export default CompFour
-
组件中数据的挂载方式
属性:React中属性是不可变的
方式:外部传入 内部定义
-
外部传入
import React,{Component,Fragment} from 'react' export default class PropComp extends Component{ render(){ return ( <Fragment> <p> 外部传入 : {this.props.name}</p> </Fragment> ) } }
import React,{ Component,Fragment } from 'react' import PropComp from './components/PropComp'; import StateComp from './components/StateComp'; class App extends Component{ render (){ const name = 'gj' return ( //jsx结构-要有为一根元素, <Fragment>可以充当唯一根元素并且不会在页面中展示 <Fragment> <PropComp name = { name }></PropComp> <StateComp/> </Fragment> ) } } export default App
-
内部定义
import React,{Component,Fragment} from 'react' export default class PropComp extends Component{ /* * 当前组件内是: * 属性一旦确定就不可更改了 * 如果是外部传入的属性,我们要通过外部来修改的 */ //属性内部添加 static defaultProps = { zhi: '我是最棒的' } render(){ return ( <Fragment> <p> 内部定义: {this.props.zhi}</p> </Fragment> ) } }
属性验证:
-
首先安装:yarn add prop-types cnpm i prop-types -D
-
import React,{Component,Fragment} from 'react' import PropTypes from 'prop-types' export default class PropComp extends Component{ //属性内部添加 static defaultProps = { zhi: '我是最棒的' } render(){ return ( <Fragment> <p> 外部传入 : {this.props.name}</p> <p> 内部定义: {this.props.zhi}</p> </Fragment> ) } } PropComp.propTypes = { name:PropTypes.string }
状态
-
实例属性形式
import React,{ Component,Fragment} from 'react' export default class StateComp extends Component{ /* * 记住了: * state只能在当前组件中定义,也只能在当前组件中修改 * 实例属性定义形式 ! 构造函数定义形式 - 推荐 */ state = { info:'冷' } render(){ return ( <Fragment> <h3>状态的定义</h3> <p> {this.state.info}</p> </Fragment> ) } }
-
放在constructor里面 【 推荐 】
import React,{ Component,Fragment} from 'react' export default class StateComp extends Component{ constructor () { super() this.state = { aaa: '热' } } render(){ return ( <Fragment> <h3>状态的定义</h3> <p> {this.state.info}</p> </Fragment> ) } }