有了JSX语法,我们可以像处理模板一样,完成变量等和Html元素的交互(如果不好理解,就看成一段html,将变动的地方打上个标记,调用时进行替换,最终不同变量生成的html不同),当然JSX并不是一个模板引擎,它是通过语法糖的形式达到了这样的效果,通过这个语法编写的代码呈现形式上又类似Html元素。虽然类似Html元素,但又有了动态的变化能力,我们可以对这些代码其抽象成可复用的模块,也就是组件,这些组件通过暴露的属性接收外界的变化,也就是props的这个东西,组件就通过props获知个属性的变化值,完成和组件外部的互动。
在这里特别说明一下,针对React的组件,里面又分了有状态(class定义)和无状态(function定义)组件,我们先简单了解就好,后续你会发现通过React Hooks的引入使用无状态组件基本都可以解决,重要的是我们需要理解状态(State)这个东西
1.2 是围绕State的作用范围和生命周期。
有了元素组件,也就有了可以通过控制参数来完成对dom元素操作完成页面变化的能力,但如何和数据进行连接,这时我们就引入状态的概念,也就是State对象。一旦State状态对象发生变化(setState方法触发),对应组件就会进行重新渲染,以完成数据对页面的驱动。当然在这个渲染过程中,React内部进行了很多优化,比如通过虚拟dom树的对比,只有真正变化的元素才会重新渲染,尽可能的提升和保证性能。
这里需要说明React和Vue、Angular的一个重要不同:State的数据和元素的绑定是单向的,State的变化会驱动页面元素变化,但页面输入框等的值变化并不会直接影响到State。单向还是双向各有优劣,React的作者们已经做出了选择,我们不必纠结。
因为State是一个状态对象,就会存在一个作用的上下文范围和生命周期管理,否则相互覆盖或者常驻内存就会引发各种未知问题。
a. 关于作用范围:
上边说了组件和外部的交互通过Props可以进行,本着职责统一,State就不需要参与外边的事情,专职服务于组件内部即可。这样组件内部数据管理在State中,外部通过Props传入,多层级嵌套引用时相互不会造成数据污染。
组件状态发生变化,组件本身及相关联的子组件接收到变化完成变动,这种层层的嵌套,再加上State在数据绑定的单向特性,数据就像一个金子塔一样由塔尖传递到塔底。所谓的React数据在组件层面是向下流动的就容易理解了。(当然父组件可以传递方法给子组件,子组件事件执行时触发对父级组件的回调)
b. 关于生命周期
了解了状态的作用范围,我们就可以很好理解它的生命周期了,因为它仅需服务组件本身,随着组件渲染卸载一起生存即可。
以此为依据我们可以很轻易的理解一下两个流程
组件新建生命过程:1. 初始化构造组件 =》 2. 获取父组件传入的Props =》3. 初始化状态对象 =》 4.准备渲染 =》 5. 实际渲染呈现 =》6. 渲染页面完成
组件更新生命过程:1. 接收父组件传入的Props =》2. 组件更新判断(如果需要继续) =》 3. 准备更新 =》 4. 实际渲染呈现 =》 5. 更新组件完成
更新过程中如果状态变化来自自身,跳过第一步。除了上边的两个流程,还有一个独立的事件,就是组件无需展示时卸载事件。这里不具体列出对应过程的方法名称,没有意义,我们主要了解处理的过程。特别是在后续的真正使用时,我们不会有太多机会需要直接操作相关事件。
一个简单的组件定义示例:
function Welcome(props) { return <h1>Hello, {props.name}</h1>; }