浅谈react组件

组件化思想

vue和react都是现在最火的两大前端框架之一,无论是vue,还是react,他们都采用的是组件化的思想。对于一个前端开发人员来说,组件这个词并不陌生,也可以感受到组件所带来的好处与快感。

我就随性的讲讲我个人对组件化思想的看法,组件化并不是前端所特有的,在很多方面都会涉及到。我把它带来的好处分类两个大的方面:

  • 把复杂的问题进行拆分,简化问题
  • 提高公共内容的复用性,灵活性

再通俗易懂的来说,就好比搭积木一样,假如我们需要做一个火车模型,我们会在众多的零散的积木零件中,找到所需要用到的零件,然后对他们进行合理的组合,最终拼成我们想要的东西。而不是你需要一个火车,乐高就直接给你做一个火车,你需要一个飞机,又重新给你做一个飞机,遇到一些难缠的甲方,当你给他做了一个飞机后,甲方爸爸觉得某个部位不满意,你又要重新去做一个飞机。如果是使用零散的组件搭建的话,可以对某个局部进行方便快捷的调整。

有了组件化的思想还不够,还要知道如何去划分组件,不是说组件划分的越小越好,在保证组件可以被灵活复用的前提下,减少无用的不必要的组件划分。

vue组件与react组件

在vue中,一个.vue文件就为一个组件,当然对于一个跟组件来说你也可以把它做为一个页面。

在react中,组件的形式更加的灵活,分为函数式组件和class组件,在一个js或jsx文件中,我们可以创建任意多个组件。

每个组件从诞生到结束都会经历一个生命周期,VUE中可分为4大阶段:创建、挂载、更新、销毁,每个阶段又可分成两个周期,详情如下:

  • beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
  • created:data和methods已经创建完成,准备编译模板
  • beforeMount:完成模板编译,但未挂载到页面中
  • mounted:将模板挂载对应的容器中
  • beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
  • updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染
  • beforeDestroy:实例被销毁之前调用,此时实例还可用
  • destroyed:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁

react组件的生命周期可分为3个状态

  • Mounting:已插入真实 DOM

  • Updating:正在被重新渲染

  • Unmounting:已移出真实 DOM
    具有以下方法:

  • componentWillMount:在渲染前调用,在客户端也在服务端。

  • componentDidMount:在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过- this.getDOMNode()来进行访问。如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。

  • componentWillReceiveProps:在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。

  • shouldComponentUpdate:返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
    可以在你确认不需要更新组件时使用。

  • componentWillUpdate:在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。

  • componentDidUpdate:在组件完成更新后立即调用。在初始化时不会被调用。

  • componentWillUnmount:在组件从 DOM 中移除之前立刻被调用。

react组件

无论是哪种组件,他们的本质还是应该做一个组件应该做的事情。

一个组件可以分为输入、输出、状态三个部分

  • 输入(props):父组件传递的内容
  • 输出(render/return):返回所需要渲染的内容
  • 状态(state):可以看做是充当辅助的角色,为了达到所需要的结果所需要的一些必要的中间桥梁,简单说,就是普通的数据

上面提到了react的组件有两种形式,他们是不是没有任何区别,或者说是在任何情况下都可以互换使用呢。

当然不是,我们通过一个例子来看看他们的不同。

class Component extends React.Component {
  constructor(props) {
  super(props)
  this.state = {
  value: 0,
      }
    }
    componentDidMount(){
      setInterval(() => {
  this.setState({
  value: this.state.value + 1
        })
      }, 1000);
    }
    render() {
  return 

函数式组件

{/*函数式组件*/}

class组件

{/*class组件*/}
} }

上面有一个组件,这里作为父组件,父组件中有一个名为value的状态变量,在componentDidMount中有一个定时器,其作用是每隔1秒后,使value的值+1。

接下来我们就分别使用函数式和class的形式写两个子组件,他们具有相同的功能。

//函数式组件
function FunComponent(props){
  let {count} = props
  let handleClick = () => {
    setTimeout(() => {
      alert(count)
    }, 3000);
  }
​
  return (
    

当前数量:{count}

) }
//class组件
class ClassComponent extends React.Component {
  constructor(props){
  super(props)
  this.state = {
      }
    }
    handleClick = () => {
      setTimeout(() => {
        alert(this.props.count)
      }, 3000);
    }
    render() {
  return 

当前数量:{this.props.count}

} }

在子组件中,接收并显示父组件传递的value值,并有一个按钮,点击按钮3秒后弹出显示value值。

浅谈react组件_第1张图片

在无任何操作的情况下,他们的值同步的变化,因为他们都接收自同一个父组件所传递的值。

现在点击第一个按钮,3秒后弹出的count值与当前页面中显示的count值是不同的,而是等于点击按钮时的值。

浅谈react组件_第2张图片

点击class组件中的按钮,3秒后弹出的count值与当前页面中显示count值相同。
浅谈react组件_第3张图片

在某些情况下, 函数组件中的行为才符合预期。如果将 setTimeout 类比到一次 Fetch 请求,在请求成功时,我要获取的是发起 Fetch 请求前相关的数据,并对其进行修改。

为什么会产生这种差异?

在 class 组件中,我们是从 this 中获取到的 props.count。this 是固定指向同一个组件实例的。在 3 秒的延时器生效后,组件重新进行了渲染,this.props 也发生了改变。当延时的回调函数执行时,读取到的 this.props 是当前组件最新的属性值。

而在 函数组件中,每一次执行 render 函数时,props 作为该函数的参数传入,它是函数作用域下的变量。这样理解,在组件首次被创建时,就相当于调用了一次函数,当count值发生改变后,又一次调用了该函数,每一次调用之间都是相互独立的,而props就是该函数的参数,每个函数在被调用时,它的参数就已经被确定,不会被其他函数所影响。

你可能感兴趣的:(React)