原则

  • props一定配上校验和default
  • 少用生命周期,多用statelessPureComponent

JSX

{}里面可以放任意js表达式,想实现vue中v-for的效果,可以用:{ arr.map(xxx) }来实现

写法:标签属性:class->className,事件监听:onclick->onClick,style使用: font-size: 12px; color: red; -> {fontSize: '12px', color: 'red'}

组件

state与setState

内部数据用state(可以叫组件的状态),但不允许直接更改,要修改state,只能用setState,setState不一定是异步的

在由React控制的事件处理过程中,会有state的合并过程,因此状态改变是异步的,而绕过React通过js原生addEventlistener直接添加事件处理函数,使用定时器等React无法掌握的API就会出现同步刷新情况

异步情况,如何利用上一次的值?

setState((prevState, props) => {
    count: prevState.count + 1;
})
setState((prevState, props) => {
    count: prevState.count + 1;
})

还可以利用生命周期:第一次count+1只会触发componentDidUpdate,将第二次count+1操作直接放入componentDidUpdate函数中

props

接受外部数据(可以叫组件的属性),vue需要使用冒号才是props,react不需要冒号,类似于vue的emit是通过props传入一个函数,然后子组件调用函数实现

生命周期

React在组件的出生,存在,消亡的过程中提供了一些回调函数给我们使用,分为挂载,更新,卸载三个阶段,

挂载阶段:

  1. constructor()
  2. componentWillMount()
  3. render()
  4. componentDidMount()

初始化数据在constructor中,异步加载数据在componentDidMount

ps:React.js 将组件渲染,并且构造 DOM 元素然后塞入页面的过程称为组件的挂载

更新阶段:

React更新组件有三种途径,父组件更新、自身状态变化、自身强制更新

父组件更新时,子组件也需要重新渲染:

  1. componentWillReceiveProps()
  2. shouldComponentUpdate()
  3. componentWillUpdate()
  4. render()
  5. componentDidUpdate()

自身状态变化时(调用setState):

  1. shouldComponentUpdate()
  2. componentWillUpdate()
  3. render()
  4. componentDidUpdate()

强制更新时(调用forceUpdate):

  1. componentWillUpdate()
  2. render()
  3. componentDidUpdate()

其中shouldComponentUpdate特别有用,可以提升性能,返回false组件就不会重新渲染(例如purecomponent),componentWillReceiveProps一般用来将新的props同步到state

卸载阶段:

组件被卸载,执行componentWillUnmount函数,会进行清除定时器,解绑自定义事件等清理工作

context

是一个React独特的概念:

React.js 的 context 其实就像是组件树上某颗子树的全局变量,某个组件只要往自己的 context 里面放了某些状态,这个组件之下的所有子组件都可以直接访问这个状态而不需要通过中间组件的传递,父组件是不能访问到的

使用:

// 验证 getChildContext 返回的对象(必写)
static childContextTypes = {
    themeColor: PropTypes.string
}
// getChildContext 这个方法就是设置 context 的过程,它返回的对象就是 context
getChildContext () {
    return { themeColor: this.state.themeColor }
}

子组件中访问context,只需:

// 声明和验证你需要获取的状态的类型(必写)
static contextTypes = {
    themeColor: PropTypes.string
}
// 使用:
this.context.themeColor

ps:context 里面的数据能被随意接触就能被随意修改,不要使用!

ref

一些场景会需要操作dom:进入页面以后自动 focus 到某个输入框;动态获取某个 DOM 元素的尺寸来做后续的动画等,这时就需要用ref(除非必须,不然不用,影响性能)

使用:<input ref={(input) => this.input = input} />,此时this.input就代表了 input这个元素

children

类似于vue的slot,但不像slot有具名和匿名这样的区别,React就直接使用props.children即可,<Card><h2>React.js 小书</h2></Card>,此时再在Card组件里面用this.props.children就会返回一个对象数组了

原生html

想要显示原生的html内容,vue中是使用的v-html,React中使用的是dangerouslySetHTML,但是每次使用的时候第一反应就应该想到xss攻击,使用<div dangerouslySetInnerHTML={{__html: this.state.content}} />,例如富文本的场景比较有用

相关概念

状态提升:当某个状态被多个组件依赖或者影响的时候,就把该状态提升到这些组件的最近公共父组件中去管理,用 props 传递数据或者函数来管理这种依赖或着影响的行为

纯函数:一个函数的返回结果只依赖于它的参数,并且在执行过程里面没有副作用,我们就把这个函数叫做纯函数

函数式组件:就是一个函数(其实class定义的类也是一个函数),没有自身状态,不需要继承React.Component

import React from 'react';
// 传入props,可以配合解构使用
function Hello({name}) {
    return <div>{name}</div>;
}
// 属性默认值和属性类型只能通过这种方式定义
Hello.propTypes = {
    name: React.PropTypes.string
}
Hello.defaultProps = {
    name: 'xxx'
}

PureComponentPureComponent继承自Component,并将isPureReactComponent属性设置为true,和Component的功能基本一样,但是PureComponentshouldComponentUpdate会对propsstate进行浅层的比较:

import { PureComponent } from "react";

class Demo1 extends Component {
  shouldComponentUpdate(nextProps, nextState) {
    const { props, state } = this;
    function shallowCompare(a, b) {
      return a === b || Object.keys(a).every(k => a[k] === b[k]);
    }
    return shallowCompare(nextProps, props) &&  shallowCompare(nextState, state);
  }
}
// Demo1与Demo2等价
class Demo2 extends PureComponent {}

高阶组件:它是一个函数,传给它一个组件,它返回一个新的组件,这个新的组件会使用你传给它的组件作为子组件,目的就是为了组件之间的代码复用,高阶组件内部的包装组件和被包装组件之间通过 props 传递数据

需要注意的事项和原则:

  1. 高阶组件不可以直接修改接受组件的自身行为,只能进行功能组合
  2. 高阶组件是纯函数,需要保证没有副作用
  3. 在进行功能组合时,一般通过增加不相关的props的形式给原有组件传递信息
  4. 不要在render方法中使用高阶组件
  5. 高阶组件不会传递ref

end:没记录React技术栈中其他的部分,例如react-redux到react-soga到dva以及react-router等,由于这些部分更深入于软件工程和框架使用模块,后续再跟进...

参考链接:

React.js小书

React状态管理与同构实战

标签: none

添加新评论