如何将react文件引用到项目上面
- 引入.js文件来使用React
缺点:需要用script标签引入外部被拆分的js文件页面,导致页面加载慢,性能低,维护性差
- 通过脚手架工具来编码
脚手架工具是前端开发过程中的辅助工具,会自动构建大型项目的开发流程和目录,允许我们以一定的方式实现js文件的相互引用,更方便的对项目进行管理,但是在脚手架里面写的代码不能直接运行,需要脚手架工具帮我们编译,编译出来的代码才能被浏览器识别运行,一般使用grunt、gulp、webpack等工具来帮助编写脚手架工具。react官方提供的脚手架工具是create-react-app
安装create-react-app
全局安装create-react-app
npm install -g create-react-app
运行create-react-app命令创建react项目(项目名称不能有字母大写也就是不能驼峰命名)
create-react-app project-name
运行react项目
npm run start
react开发的特点
声明式开发
可以与其他框架并存
组件化
单向数据流
视图层框架
函数式编程
命令式开发
像jquery或者js很多代码都在操作DOM
声明式开发
节约多余的dom操作,只需要思考怎么去操作数据
可以与其他框架并存
比如Todolist这个就只会去操作index.html文件里面id为root的DOM元素,不管index.html里面的其他DOM元素,所以jquery这类的库或者其他的都能够与React框架并存
组件化
父子组件之间的传值
单向数据流
父组件可以向子组件传值,但是子组件不能直接去改变这个值,只能去使用这个值,子组件只能通过触发事件调用父组件的方法才能实现值得修改
视图层框架
上面那个紫色组件要想和标识的灰色组件实现通信,就必须按照箭头指示那样实现多次父子组件之间的通信,十分麻烦,所以在大型项目的开发中还需要借助数据层框架(比如redux中间件)进行开发
函数式编程
1.维护容易,可以对函数进行拆分,让函数能够各司其职
2.有利于进行前端自动化测试
安装React开发调试工具
表示处于开发环境的项目
表示该页面不是使用react开发的
表示使用react开发并且该项目是已经上线了的项目
React一些重要的点
React key值相关
react中的key属性,它是一个特殊的属性,它的出现不是给开发者用的(例如你为一个组件设置key之后,也仍无法获取这个组件的key值),而是给react自己用的。简单来说,react利用key来识别组件,它是一种身份标识标识,就像我们的身份证用来辨识一个人一样。每个key对应一个组件,相同的key react认为是同一个组件,这样后续相同的key对应组件都不会被创建。
在项目如果我想要使用key值就会出现上图的警告
什么是虚拟DOM
第一种实现思路:
1.state数据
2.JSX模板
3.数据+模板结合,生成真实的DOM来显示
4.state发生改变
5.新的数据+模板结合,生成真实的DOM替换原始的DOM
缺陷:
第一次生成了一个完整的DOM片段
第二次生成了一个完整的DOM片段
第二次的DOM替换第一次的DOM,非常耗性能
第二种实现思路:
1.state数据
2.JSX模板
3.数据+模板结合,生成真实的DOM来显示
4.state发生改变
5.新的数据+模板结合,生成真实的DOM,并不直接替换原始的DOM
6.新的DOM(DocumentFragment)和原始的DOM做比对,找差异
7.找出input框发生了变化
8.只用新的DOM中的input元素替换掉老的DOM中的input元素
缺陷:
性能的提升并不明显
第三种实现思路:虚拟DOM方案
1.state数据
2.JSX模板
3.数据+模板结合,生成真实的DOM来显示
<div id='abc'><span>hello world</span></div>
4.生成虚拟DOM(虚拟DOM就是一个JS对象,用它来描述真实的DOM) (损耗了性能)
['div',{id:'abc},['span',{},'hello world']]
5.state发生变化
6.数据+模板生成新的虚拟DOM(极大的提升了性能)
['div',{id:'abc},['span',{},'bye bye']]
7.比较原始虚拟DOM和新的虚拟DOM的区别,找到区别是span中的内容(极大地提升了性能)
8.直接操作DOM,改变span中的内容
优点:
1.性能提升了
2.它使得跨端应用得以实现。react native,在原生的应用里面是不存在DOM概念的,在浏览器里面虚拟DOM可以转化为真实的DOM,而在原生应用里面,虚拟DOM可以转化为一些原生的组件
深入理解虚拟DOM:
JSX --> createElement(jsx语法创建的并不是真实的DOM,使用createElement完全可以实现,JSX的出现是为了方便写出简洁的代码) --> 虚拟DOM(JS对象) --> 真实的DOM
在render里面
return <div><span>item</span></div>
实际上面等同于下面
return React.createElement('div',{},React.createElement('span',{},'item));
虚拟DOM里面的DIFF算法:
比较原始虚拟DOM和新的虚拟DOM的区别,diff的意思就是difference
什么时候数据会发生变化,都是因为调用setState数据才发生了变化,虚拟DOM才会发生比对,setState实际上是异步的,为了提升底层的性能,如果在较短的时间里面,连续调用了几次setState,react不会去连续进行几次虚拟DOM的比对,而是比几次setState合并成一次调用
同层比对:原始虚拟DOM与新的虚拟DOM同层的节点如果出现了差异,那么就放弃该节点下面的子节点,删除这些子节点,重新生成DOM去替换原始页面上的DOM,因此可能会造成DOM节点渲染的浪费及复用性,但是这种比对的算法简单,比对速度比较快
key值的比对:虚拟DOM的比对会根据key值做关联。没有key值的话,可能会循环新老虚拟DOM节点,一个一个节点去做比对。给每个DOM节点设立了key值之后,新老虚拟DOM上key值相同的节点发生改变时能够准确进行定位,能够提升比对的性能,为什么在循环中key值不要设置为index,因为key值会不稳定,新老虚拟DOM上面的节点会对不上
React中ref的使用
ref相当于reference,在react中可以使用ref操作DOM,尽量不要使用,ref和setState合用的时候会出现一些坑,因为setState是异步加载的,要解决这个问题,只有在setState里面多加一个回调函数
生命周期函数
指在某一时刻组件会自动调用执行的函数
initialization:初始化阶段
Mounting:组件第一次被放到页面上的时候
componentWillMount:
componentWillMount(){
console.log('只会在第一次render前执行一次componentWillMount函数');
}
componentDidMount:
componentDidMount(){
console.log('只会在第一次render后执行一次componentWillMount函数');
}
react提升性能的一些点:
1.把函数作用域的修改放到constructor里面去修改this指向
2.setState异步调用
3.虚拟DOM,同层比对,key值比对
4.shouldComponentUpdate
使用charles进行接口数据模拟
下载charles:
charles下载:https://www.charlesproxy.com/
创建json文件
componentDidMount(){
axios.get('/api/todolist')
.then((res)=>{console.log(res)})
.catch(()=>{console.log('error')})
// console.log('componentDidMount');
}
react-transition-group实现动画
https://github.com/reactjs/react-transition-group
cnpm install react-transition-group --save
Redux概念简介
Redux = Reducer + Flux(公共数据存储区域可以有很多store组成,导致数据存储会产生存储依赖的问题)
store:存储数据的公共区域(图书馆的管理员)
React Components:页面上的react组件(借书的用户)
Reducers:(图书馆的管理员没有办法记住图书馆所有图书的存储情况的,需要通过记录本来记录)
Action Creators:数据的传递(用户说的要借什么书的话)
store的创建
安装包:
cnpm install --save redux
Action和Reducer的编写:
Redux设计和使用的三项原则
store是唯一的
只有store能够改变自己的内容,store从reducer拿到数据后,自己进行数据更新,不是reducer去修改store的数据,就像this.state一样
reducer必须是纯函数(给定固定的输入,就一定会有固定的输出,而且不会有任何副作用)
Redux核心的API
createStore
store.dispatch
store.getstate
store.subscribe
在react项目中使用ant design框架
cnpm install antd --save
cnpm install react-app-rewired -D
cnpm install babel-plugin-import -D
UI组件与容器组件的拆分
ui组件(傻瓜组件):负责页面的渲染
容器组件(聪明组件):负责页面的逻辑
使用Redux-thunk中间件进行ajax请求发送
如果把异步的请求或者非常复杂的逻辑都放到组件里面,组件会显得很臃肿。我们可以把这些移到别的地方进行统一的管理
cnpm install redux-thunk
当使用了redux-thunk之后,把异步操作放到action里面去操作,有利于代码的拆分和自动化测试,Action可以作为一个函数使用了,而不仅仅是作为一个对象使用
中间件的概念
什么和什么的中间
redux-thunk是对dispatch方法的一个升级,当调用dispatch方法时,如果传进去的action是一个对象,那么dispatch方法就会直接把action对象传给store;如果传进去的action是一个函数,此时的dispatch方法已经升级了,dispatch方法不会把这个方法直接传递给store,会把函数(这个函数有一个dispatch的函数等同于store.dispatch函数)先执行,执行这个函数的最后调用dispatch方法返回一个对象给store。也就是说dispatch升级之后会根据参数的不同执行不同的事情,在没有升级之前dispatch只能接收一个对象,接受的不是对象时会报错。
Redux-saga中间件的使用
cnpm install --save redux-saga
React-Redux的使用
cnpm install react-redux