浅谈React组件

Posted 前端筱园

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈React组件相关的知识,希望对你有一定的参考价值。



组件化思想


浅谈React组件

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


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

  • 把复杂的问题进行拆分,简化问题

  • 提高公共内容的复用性,灵活性

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

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



浅谈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组件

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 <div> <div> <div> <h3>函数式组件</h3>             {/*函数式组件*/} <h3>class组件</h3>             {/*class组件*/} </div> </div> </div> } }
上面有一个组件,这里作为父组件,父组件中有一个名为value的状态变量,在componentDidMount中有一个定时器,其作用是每隔1秒后,使value的值+1。
接下来我们就分别使用函数式和class的形式写两个子组件,他们具有相同的功能。
  
    
    
  
//函数式组件 function FunComponent(props){ let {count} = props let handleClick = () => { setTimeout(() => { alert(count) }, 3000); }
return ( <div> <p>当前数量:{count}</p> <button onClick={handleClick}>Alert Count</button> </div> ) }

  
    
    
  
//class组件 class ClassComponent extends React.Component { constructor(props){ super(props) this.state = { } } handleClick = () => { setTimeout(() => { alert(this.props.count) }, 3000); } render() { return <div> <p>当前数量:{this.props.count}</p> <button onClick={this.handleClick}>Alert Count</button> </div> } }
在子组件中,接收并显示父组件传递的value值,并有一个按钮,点击按钮3秒后弹出显示value值。
浅谈React组件
在无任何操作的情况下,他们的值同步的变化,因为他们都接收自同一个父组件所传递的值。

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

点击class组件中的按钮,3秒后弹出的count值与当前页面中显示count值相同。    

浅谈React组件

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


为什么会产生这种差异?


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

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

以上是关于浅谈React组件的主要内容,如果未能解决你的问题,请参考以下文章

浅谈react受控组件与非受控组件

浅谈React工作原理

浅谈React

浅谈ReactJS中key的作用 你真的知道吗

Reactreact概述组件事件

前端知识 |浅谈React setState