TodoList
- 安装create-react-app
npm install -g create-react-app
- 创建项目
create-react-app jianshu
state 和 props
- 当组件的
state或者props发生改变的时候,render函数就会重新执行。 - 当父组件的render函数被执行的时候,子组件的render函数也会被重新执行。
PropTypes 和 defaultProps
import PropTypes from 'prop-types'
TodoItem.propTypes = {
test: PropTypes.string.isRequired,
item: PropTypes.string,
delelte: PropTypes.func,
index: PropTypes.number
}
TodoItem.defaultProps = {
test: 'hello world'
}
虚拟DOM
- 数据 state
- 模板 JSX
- 数据 + 模板生成虚拟DOM(虚拟DOM是一个JS对象,用它来描述真实的DOM)【损耗了性能但是极小】
['div',{id:'abc'},['span',{},'Hello world']]
- 用虚拟DOM的结构生成真实的DOM来显示
- state发生变化
- 数据+模板 生成新的虚DOM ['div',{id:'abc'},['span',{},'bye bye']]
- 比较原始虚拟DOM与新的虚拟DOM的区别,找到区别替换差异的内容【极大地提升了性能】
- 直接操作dom,改变span中的内容
- JSX ->createElement ->虚拟DOM(JS对象)->真实的DOM
虚拟DOM的优点
- 减少了真实DOM的创建与对比,DOM的比对变成JS对象的对比,性能提升了
- 使得跨端应用得以实现。React Native
JSX的本质
- JSX语法根本无法被浏览器识别解析
- JSX代码
- 解析后的结果
React.createElement('div',{id:'div1',[]})
- JSX是React引入的,但不是React独有的
- React已经将JSX作为一个独立的标准开放
- React.createElement是可以自定义修改的
ref
<input this.ref = {(input)=>{this.input = input}/>
React的声明周期函数
组件在某一时刻会自动执行的函数
componentWillMount
在组件即将被挂载到页面的时候自动执行
render
必须有的声明周期,因为React组件是继承自Component,Component内部已经内置了其他声明周期钩子,唯独没有内置render函数
componentDidMount
在组建被挂载到页面之后自动执行
shouldCompoentUpate
组件被更新之前调用
shouldComponentUpdate(nextProps,nextState){
return true/false //返回一个布尔值
}
componentWillUpdate
组件被更新之前,shouldComponentUpdate之后,如果shouldComponentUpdate返回true,componentWillUpdate会被执行,否则不会被执行
componentDidUpdate
组件更新完成之后会被执行
componentWillUnmount
当组件即将从页面中移除的时候被执行
componentWillReceiveProps
当一个子组件从父组件接受参数,只要父组件的render函数被重新执行了,子组件的componentWillReceiveProps会被执行,即子组件第一次存在于父组件中,不会执行,子组件之前已经存在于父组件中,才会执行。
Recat 调试工具:React Developer Tools
直接安装Chrome插件不需要任何配置,注意安装之后关闭浏览器重新启动即可。
React中性能优化的点:
- bind(this)在constructor中做,保证了整个组件中函数的绑定只会执行一次
- React底层setState会合并(内置的性能提升机制)
- React底层虚拟DOM 同层比对,key值比对
- shouldComponentUpdate提高组件性能
React请求在哪里发送
一般我们约定在ComponentDidMount中发送接口请求。
UI组件
是一个类定义的组件,只有render函数
无状态组件
无状态组件是一个函数
ComponentWillMount 也会执行一次,为什么不在ComponentWillMount中发送?
- 在写网页的时候没有问题,这么做没有问题。
- 在React 16中,componentWillMount可能在一次渲染中多次调用。而且之后的React版本中,componentWillMount可能在一次渲染中多次调用将会被废弃。
- 但是如果是在react native 或者服务器端,就会产生问题:
- 在服务器渲染时,如果在 componentWillMount 里获取数据,fetch data会被执行两次,一次是在服务端,一次是在客户端,就造成了多余的请求。
为什么不在render中发送?
因为render会被反复执行执行,造成死循环
使用axios进行接口请求
import Axios from 'axios'
componentDidMount () {
Axios.get('/myapi/todolist')
.then(() => {
alert('success')
})
.catch(() => {
alert('fail')
})
}
react-transition-group
安装
yarn add react-transition-group
使用
单个动画的使用的使用
import { CSSTransition } from 'react-transition-group'
//JSX模板代码
<CSSTransition
in={this.state.show}
timeout={1000}
classNames='fade'
unmountOnExit>
<div>hello</div>
</CSSTransition>
<button onClick={this.handleToggle}>toggle</button>
//JS处理程序
handleToggle () {
this.setState({
show: !this.state.show
})
}
//CSS
.fade-enter{
opacity: 0;
}
.fade-enter-active{
opacity: 1;
transition: opacity 1s ease-in;
}
.fade-enter-done{
opacity: 1;
}
.fade-exit{
opacity: 1;
}
.fade-exit-active{
opacity: 0;
transition: opacity 1s ease-in;
}
.fade-eixt-done{
opacity: 0;
}
整组的使用
//JSX模板
<TransitionGroup>
{
this.state.list.map((item, index) => {
return (
<CSSTransition
timeout={1000}
classNames='fade'
unmountOnExit
key={index}>
<div >{item}</div>
</CSSTransition>)
})
}
</TransitionGroup>
//js
handleAddList () {
this.setState((prevState) => {
return {
list: [...prevState.list, 'item']
}
})
}
//css同单一使用
合成事件
setState()是同步的还是异步的?
- setState()在合成事件和生命周期中的表现是异步的,在setTimeout和原生事件中的表现是同步的。
- setState()的异步并不是说内部的实现是异步代码,而是因为setState()之后,需要经过 React 对 state 的所有改变进行合并处理之后,才会去计算新的虚拟dom,再根据最新的虚拟dom去重新渲染真实dom。
- React 内部会维护着一个 state 的更新队列,每次调用 setState 都会先把当前修改的 state 推进这个队列,在最后,React 会对这个队列进行合并处理,然后去执行回调。根据最终的合并结果再去走下面的流程(更新虚拟dom,触发渲染)。
- React中会去维护一个标识(isBatchingUpdates),判断是直接更新还是先暂存state进队列。setTimeout以及原生事件都会直接去更新state,因此可以立即得到最新state。而合成事件和React生命周期函数中,是受React控制的,其会将isBatchingUpdates设置为 true,从而走的是类似异步的那一套。
setState()为什么设计成 ’异步‘ 的?
为了提高性能,将多次state的修改合并,然后再去更新虚拟DOM,再触发DOM操作。
styled-components
- yarn add styled-components
- reset.css
说一下setState的过程
setState是异步的,vue修改属性也是异步的
- 每个组件实例都有renderComponent方法(这个方法在React.Component中)
- 执行renderComponent会重新执行实例的render方法
- render方法返回newVnode,然后拿到preVnode
- 执行patch(preVnode.newVnode)
setState为何要异步
- 可能一次执行多次setState
- 你无法规定限制用户如何使用setState
- 没必要每次setState都重新渲染,考虑性能
- 即便是每次重新渲染,用户也看不到中间的效果
React VS Vue
两者的本质区别
- vue本质是MVVM框架,由MVC发展而来
- React本质是前端组件化框架,由后端组件发展而来
模板和组件化的区别
- vue 使用模板,模板分离上面,我更倾向于vue
- React 使用JSX, 模板语法上,更加倾向于React
- React本身就是组件化,没有组件化就不是React
- Vue也支持组件化,不过是在MVVM上的扩展
两者的共同点
- 都支持组件化
- 数据驱动视图
技术选型没有对与错,技术选型要考虑的因素非常多
国内使用,首推vue,文档更易读,易学,社区够大
如果团队水平较高,推荐使用React,组件化和JSX
说一下对组件化的理解
组件的封装
- 封装视图
- 封装数据
- 变化逻辑:数据驱动视图变化
组件的复用
- 通过传递props传递 复用组件
JSX和vdom的关系
为什么需要vdom
- vdom是React初次推广开来的,结合JSX
- JSX就是模板,最终被渲染成html
- 初次渲染+ 修改state后的re-render
- 正好符合vdom的场景
自定义组件的解析
- div直接渲染成,vdom可以做到
- Input 和 List 是自定义组件(类),vdom默认不认识
- 因此Input和List定义的时候必须声明render函数
- 根据props初始化实例,然后执行实例的Render函数
- render函数返回的还还是vnode对象
为什么看起来没有引用React类,还要引入React
以为JSX语法是React.createElement()的语法糖,即使没有主动的调用React类,只要用到了JSX语法的地方就要引入React
React的合成事件
React的合成时间没有绑定到具体的DOM节点上,而是绑定在document上。