React

207 阅读7分钟

TodoList

  1. 安装create-react-app
npm install -g create-react-app
  1. 创建项目
create-react-app jianshu

state 和 props

  1. 当组件的state或者props发生改变的时候,render函数就会重新执行。
  2. 当父组件的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

  1. 数据 state
  2. 模板 JSX
  3. 数据 + 模板生成虚拟DOM(虚拟DOM是一个JS对象,用它来描述真实的DOM)【损耗了性能但是极小】
['div',{id:'abc'},['span',{},'Hello world']]
  1. 用虚拟DOM的结构生成真实的DOM来显示
  2. state发生变化
  3. 数据+模板 生成新的虚DOM ['div',{id:'abc'},['span',{},'bye bye']]
  4. 比较原始虚拟DOM与新的虚拟DOM的区别,找到区别替换差异的内容【极大地提升了性能】
  5. 直接操作dom,改变span中的内容
  • JSX ->createElement ->虚拟DOM(JS对象)->真实的DOM

虚拟DOM的优点

  1. 减少了真实DOM的创建与对比,DOM的比对变成JS对象的对比,性能提升了
  2. 使得跨端应用得以实现。React Native

JSX的本质

  1. JSX语法根本无法被浏览器识别解析
  2. JSX代码
  1. 解析后的结果
React.createElement('div',{id:'div1',[]})
  1. JSX是React引入的,但不是React独有的
  2. React已经将JSX作为一个独立的标准开放
  3. 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中性能优化的点:

  1. bind(this)在constructor中做,保证了整个组件中函数的绑定只会执行一次
  2. React底层setState会合并(内置的性能提升机制)
  3. React底层虚拟DOM 同层比对,key值比对
  4. shouldComponentUpdate提高组件性能

React请求在哪里发送

一般我们约定在ComponentDidMount中发送接口请求。

UI组件

是一个类定义的组件,只有render函数

无状态组件

无状态组件是一个函数

ComponentWillMount 也会执行一次,为什么不在ComponentWillMount中发送?

  1. 在写网页的时候没有问题,这么做没有问题。
  2. 在React 16中,componentWillMount可能在一次渲染中多次调用。而且之后的React版本中,componentWillMount可能在一次渲染中多次调用将会被废弃。
  3. 但是如果是在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()是同步的还是异步的?

  1. setState()在合成事件和生命周期中的表现是异步的,在setTimeout和原生事件中的表现是同步的。
  2. setState()的异步并不是说内部的实现是异步代码,而是因为setState()之后,需要经过 React 对 state 的所有改变进行合并处理之后,才会去计算新的虚拟dom,再根据最新的虚拟dom去重新渲染真实dom。
  3. React 内部会维护着一个 state 的更新队列,每次调用 setState 都会先把当前修改的 state 推进这个队列,在最后,React 会对这个队列进行合并处理,然后去执行回调。根据最终的合并结果再去走下面的流程(更新虚拟dom,触发渲染)。
  4. React中会去维护一个标识(isBatchingUpdates),判断是直接更新还是先暂存state进队列。setTimeout以及原生事件都会直接去更新state,因此可以立即得到最新state。而合成事件和React生命周期函数中,是受React控制的,其会将isBatchingUpdates设置为 true,从而走的是类似异步的那一套。

setState()为什么设计成 ’异步‘ 的?

为了提高性能,将多次state的修改合并,然后再去更新虚拟DOM,再触发DOM操作。

styled-components

  1. yarn add styled-components
  2. reset.css

说一下setState的过程

setState是异步的,vue修改属性也是异步的

  1. 每个组件实例都有renderComponent方法(这个方法在React.Component中)
  2. 执行renderComponent会重新执行实例的render方法
  3. render方法返回newVnode,然后拿到preVnode
  4. 执行patch(preVnode.newVnode)

setState为何要异步

  1. 可能一次执行多次setState
  2. 你无法规定限制用户如何使用setState
  3. 没必要每次setState都重新渲染,考虑性能
  4. 即便是每次重新渲染,用户也看不到中间的效果

React VS Vue

两者的本质区别

  1. vue本质是MVVM框架,由MVC发展而来
  2. React本质是前端组件化框架,由后端组件发展而来

模板和组件化的区别

  1. vue 使用模板,模板分离上面,我更倾向于vue
  2. React 使用JSX, 模板语法上,更加倾向于React
  3. React本身就是组件化,没有组件化就不是React
  4. Vue也支持组件化,不过是在MVVM上的扩展

两者的共同点

  1. 都支持组件化
  2. 数据驱动视图

技术选型没有对与错,技术选型要考虑的因素非常多

国内使用,首推vue,文档更易读,易学,社区够大

如果团队水平较高,推荐使用React,组件化和JSX

说一下对组件化的理解

组件的封装

  1. 封装视图
  2. 封装数据
  3. 变化逻辑:数据驱动视图变化

组件的复用

  1. 通过传递props传递 复用组件

JSX和vdom的关系

为什么需要vdom

  1. vdom是React初次推广开来的,结合JSX
  2. JSX就是模板,最终被渲染成html
  3. 初次渲染+ 修改state后的re-render
  4. 正好符合vdom的场景

自定义组件的解析

  1. div直接渲染成
    ,vdom可以做到
  2. Input 和 List 是自定义组件(类),vdom默认不认识
  3. 因此Input和List定义的时候必须声明render函数
  4. 根据props初始化实例,然后执行实例的Render函数
  5. render函数返回的还还是vnode对象

为什么看起来没有引用React类,还要引入React

以为JSX语法是React.createElement()的语法糖,即使没有主动的调用React类,只要用到了JSX语法的地方就要引入React

React的合成事件

React的合成时间没有绑定到具体的DOM节点上,而是绑定在document上。