当前位置: 首页 > 科技观察

拆解高频面试题:如何理解单向数据流?

时间:2023-03-18 11:59:37 科技观察

本文转载自微信公众号《狗狗的前端世界》,作者西岭。转载本文请联系Gogo前端世界公众号。今天的主题是组件状态。State可以简单理解为数据,类似于props,但是state是私有的,完全由当前组件控制,所以组件状态指的是组件自身维护的数据。在上一篇文章中,我们也提到了很重要的一点:数据驱动的UI。意思也很简单,就是页面显示的内容完全由状态控制,这就是所谓的MVVM的概念。UI的所有改动都交给框架自己,我们只需要管理好“数据(状态)”即可。那么在React中,如何管理状态呢?这就是本章的重点,也是整个React学习的重点:组件状态管理。基本使用状态的使用非常简单。我们在类中声明了一个名为state的对象。对象中的元素是当前组件维护的状态数据。获取展示数据时,只需要在jsx中使用this.state.xx即可获取。importReact,{Component}from'react'exportclassStatesextendsComponent{//声明状态对象state={name:'xiling',age:18}render(){return(<

statestate

{/*usethis.state.xx获取数据*/>

{this.state.name}

{this.state.age}

/>)}}exportdefaultStates我们前面说过,state数据可以控制界面,那么我们如何修改状态来改变界面呢?修改state,修改state的值最直观的方式就是使用this.state={}直接修改。我们设置了一个按钮。当点击按钮时,发现this.state={}不起作用。我们应该做什么?React为我们提供了一个特殊的this.setState({})方法,我们需要调用这个.setState({})方法传入需要修改的数据,才能正确修改state的值。至于为什么,需要了解React的数据流才能理解,这里就不详细介绍了,大家记住这个规律即可。importReact,{Component}from'react'exportclassStatesextendsComponent{//声明状态对象state={name:'xiling',age:18}//箭头函数变化=()=>{//console.log(22)//this.state.name='xiling'//错误用法this.setState({name:'xiling'})}render(){return(<>

state

{/*usethis.state.xx获取数据*/>

{this.state.name}

{this.state.age}

改变状态)}}exportdefaultStatesstate的值一旦改变,JSX中使用state的地方就会自动改变。这里还有一个需要注意的地方,因为setState方法是类中的一个属性(方法),我们需要通过this来获取。所以事件绑定handler需要用箭头函数固定this的方向,一定不能用普通函数(类方法)声明,否则会因为找不到方法直接报错。自上而下的单向数据流关于数据流的问题是面试中经常出现的典型问题。一般情况下,面试官会直接问:“你是怎么理解单向数据流的?”。请注意,这不是一个单一的个体问题,而是一个复杂的数据流问题。要回答这个问题,需要解释一下:什么是数据流?为什么是自上而下的?单向数据流是什么意思?为什么是单向的?不能是双向数据流吗?单向数据流有什么作用?什么?拆开面试题,你会发现几乎面试官问的每一个字都需要解释。宝儿,这个问题可真不简单啊!那么,我该如何回答呢?说实话没有标准答案,因为数据流的问题涉及到框架本身的设计理念,需要你对框架的设计有深刻的理解,你要站在一个角度看问题框架作者;但是,对于初学者来说,这个问题显然超出了大纲。这么重要,我学不会吧?不,你需要学习很多次,这只是第一次。在开始之前,先看一段常用的JS代码:vardatas={name:'lisi',age:18}varl1=datasvarl2=l1varl3=l2l1.age=20console.log(l1.age,l2.age,l3.age)//202020l3.age=26console.log(l1.age,l2.age,l3.age)//262626你会发现不管我们修改那个变量的age属性,其他的数据都会随之改变,而道理很简单,大家共享一个内存数据。但是从赋值前后的逻辑来看,我们可以把L3节点看成孙子,L2节点看成父亲,L1节点看成爷爷。任何一个节点的数据发生变化后,所有节点的数据也会发生变化。我们可以把这种现象看成是数据在“变量节点”上的流动。然而,这样的数据流是双向的。以L2节点为例,只要数据发生变化,上层的L1节点和下层的L3节点都会随之变化。虽然这个例子不太合适,但是回到React组件,道理是一样的,所谓数据流就是组件之间的数据传递。我们用了很多篇幅来解释组件之间的值传递,实际上我们是在讲数据流这个概念的具体用法。那么,在数据流的前面加一个“单向”的定语,叫做“单向数据流”是什么意思呢?其实现在大家理解起来很简单,就是某个节点的数据发生变化后,只会影响一个方向的其他节点。如何解释所谓的自上而下?比较简单,就是数据只会影响下一层的节点,不会影响上一层的节点。用上面的例子来说明,如果L2数据发生变化,只会影响L3,不会影响L1或其他节点。这就是“自上而下的单向数据流”。那么我们就可以在React框架中明确定义单向数据流:规范数据的流向,将外部组件向内部组件传递和更新数据。那么,在具体的代码实现中是如何体现的呢?翠花,上面的代码:图片有点看不清楚。接下来看具体代码的演示://==========App=============importReact,{Component}from'react'importC1from'。/C1'exportclassAppextendsComponent{state={name:"xiling"}render(){return(

App

APP中的值:{this.state.name}

)}}exportdefaultApp//==========C1=============importReact,{Component}from'react'importC2from'./C2'exportclassC1extendsComponent{render(){return(

C1

传入C1的值(apppassed):{this.props.toC1}

)}}exportdefaultC1//==========C2=============importReact,{Component}from'react'importC3from'./C3'exportclassC2extendsComponent{state={name:this.props.toC2}changes=()=>{this.setState({name:Math.random()})}render(){return(
<h2>C2{this.changes()}}>修改

传入C2的值(C1传入):{this.state.name}

)}}exportdefaultC2//==========C3=============importReact,{Component}from'react'exportclassC3extendsComponent{render(){return(

C3

传入C3的值(从C2传入):{this.props.toC3}
)}}exportdefaultC3最后解释一下为什么?是有什么用?其实这才是这个问题的核心。不同的技术理解会从不同的角度来解释。我只是从这里的一个家庭发言。让我们想象这样一个场景:父组件的数据通过props组件传递给子组件,在子组件中更新props,导致父组件和其他关联组件的数据更新,UI渲染也会随之更新数据。毫无疑问,这将导致严重的数据混乱和不可控。因此,大多数框架都会处理这方面的问题。而React对这方面的处理是直接规定Props是只读的,不可更改的。也就是说我们之前看到的数据更新是不能直接通过this.state来操作的。如果要更新,需要使用React提供的特殊的this.setState()方法。单向数据流实际上是框架本身对数据流的一种限制。让我们现在谈谈这个。我们学习和经历的越多,我们的理解就会越深刻,我们的视角就会越全面。