定义组件时,应尽量保持组件功能的单一性,也就是一个组件只做一件事。
作用(传递数据):props的主要用作是父组件向子组件传递数据,来定制子组件的展示
实现:通过向子组件设置props属性={属性值} 实现;子组件在入参处接收属性,同时可以设置默认值(eg:function Avatar({ size = 100 }) {...})
扩展:接收的参数可以是展开语法...props,传递所有的props数据(eg:<Avatar {...props} />),但是不建议过度使用。
注意:props子组件接受属性的默认值,仅在缺少props和设置 props属性={undefined}时才生效,如果设置 props属性={null}、props属性={0}这种假值不会生效
作用(修改数据):state的主要用作是在内存中保存信息,用来后续追踪与更新数据
实现:通过内置的HOOK函数useState 实现
注意:state的使用需要尽量保持他不自我重复(例如一个数组列表,他即用于A处展示,也用于B处操作修改,尽量定义一次,不要copy多个)
由于react是单向数据流,通常数据是右上到下传入,但子组件修改state数据后,需要告知父组件更新state。他的实现方式与vue的$emit异曲同工,在子组件的引用上处自定义事件(onXXXChange),事件中可以调用useState的set方法来修改值;子组件通过onChange事件来触发自定义事件的调用。
示例:
// 父组件
function FilterableProductTable({ products }) {
const [filterText, setFilterText] = useState(''); // 定义state
// 定义子组件透传的自定义change事件onFilterTextChange
return (
<div>
<SearchBar
filterText={filterText}
onFilterTextChange={setFilterText} />
</div>
)
}
// 子组件
function SearchBar ({filterText}) {
return (<input
type="text"
value={filterText}
placeholder="Search..."
onChange={(e) => onFilterTextChange(e.target.value)} />
)
}
有时候可能用组件嵌套组件,例如vue中的slot功能。react中依然用props,与普通属性不同的是:
(1)定义被嵌套的组件时,props入参接收一个children,并将其包裹在div中渲染(可与vue的slot对比理解,react中自己封装被slot的组件)
// 在Card组件中传入一个子组件,则接收参数children
function Card({ children }) {
return (
<div className="card">
{children}
</div>
);
}
(2)被嵌套的组件引用处,直接包裹要嵌套的目标组件(可与vue的slot对比理解,react中少了一个slot参数)
export default function Profile() {
// 要把Avatar组件嵌套入Card组件中
return (
<Card>
<Avatar
size={100}
person={{
name: 'Katsuko Saruhashi',
imageId: 'YfeOqp2'
}}
/>
</Card>
);
}
开发组件要尽量保证组件的纯粹原则,这样可以安全的缓存他们,也可以避免以后迭代带来的各种Bug。即保证组件像一个数学公式,只要输入一样,输出就永远一致。类似于以下这种示例,就是不纯粹的组件:
function Cup() {
guest = guest + 1;
return <h2>Tea cup for guest #{guest}</h2>;
}
概念:组件实例从被创建到被销毁的过程称为组件的生命周期。这里大概了解,详细了解与图解可参考React 生命周期详解 - 掘金
class类组件中,每一次由状态改变导致页面视图的改变,都经过了两个阶段:render阶段和commit阶段。由class类组件创建的实例拥有的生命周期,在render阶段执行他的render函数,和DOM节点的diff算法,找出需要改变的DOM操作;在commit阶段将要改变的DOM操作提交至视图中。
在首次渲染页面时,会调用mount相关的生命周期钩子;
之后的页面渲染中,会调用Update相关的生命周期钩子;
因此mount相关的生命周期钩子只调用一次。
render阶段(初始化阶段)
- constructor:构造函数(mount相关,只执行一次)。在初始化实例的时候调用,返回一个组件实例。
? ? ? ? ? ? ? ? ? ? ? ? ? 应用场景:通常用来初始化组件的state
- getDerivedStateFromProps:(不常用)(mount、update)从更新后的props中获取State,它让组件在 props发生改变时更新它自身的内部state。
- shouldComponentUpdate:(update)判断一个组件是否应该更新。在组件准备更新之前调用。它接收两个参数,nextProps和nextState,即下一次更新的props和state。
? ? ? ? ? ? ? ? ? ? ? ? ? 应用场景:通常用来做性能优化
- render:组件中唯一必须实现的方法(mount、update)。它的返回值将作为页面渲染的视图。返回类型有:
????????????????????????????????????????(1)JSX语法的React 元素
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (2)数组返回的多个元素
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (3)字符串、数值的文本节点
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (4)boolean类型或者null:什么都不渲染
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??(5)Portals:渲染子节点到不同的子树中
commit阶段(运行中阶段)
- componentDidMount:(mount相关,只执行一次)将组件对应的DOM插入DOM 树中之后、浏览器更新视图之前调用
? ? ? ? ? ????????应用场景:通常用做依赖DOM的初始化操作、发送网络请求、订阅。
- getSnapshotBeforeUpdate:(update)在最近一次渲染提交至DOM树之前执行。
? ? ? ? ? ????????应用场景:此时DOM树还未改变,可以获取DOM改变前的信息
- componentDidUpdate:(update)在组件更新后立即调用。首次渲染不会调用该方法,但是执行时机与componentDidMount一致。他接收三个参数,分别是 prevProps、prevState、snapshot,即前一个状态的props,前一个状态的state、getSnapshotBeforeUpdate的返回值。
? ? ? ? ?????????应用场景:可以对DOM进行操作,也可以进行网络请求。
- componentWillUnmount:(Unmount)在组件卸载以及销毁之前调用。
? ? ? ? ?????????应用场景:通常用来执行组件的清理操作。例如:清除 timer、取消网络请求、清除订阅等。
注意:
示例组件:父组件A、子组件B、子组件C,首次渲染
(1)依次执行父组件A的render阶段的mount相关的钩子constructor、getDerivedStateFromPro
ps、render
(2)依次执行子组件B的render阶段的mount相关的钩子(...同上)
(3)依次执行子组件C的render阶段的mount相关的钩子(...同上)
(4)执行子组件B的commit阶段update相关的钩子componentDidMount
(4)执行子组件C的commit阶段update相关的钩子componentDidMount
(4)执行父组件A的commit阶段update相关的钩子componentDidMount
示例组件:父组件A、子组件B、子组件C。? 改变B子组件的某个状态
(1)执行B子组件的钩子:getDerivedStateFromProps
(2)执行B子组件的update相关的钩子:shouldComponentUpdate
(3)执行B子组件的钩子:render
(4)执行B子组件的update相关的钩子:getSnapshotBeforeUpdate
(5)执行B子组件的update相关的钩子:componentDidUpdate
说明:子组件的状态改变,只会执行当前子组件的生命周期函数
示例组件:父组件A、子组件B、子组件C。? 改变A父组件的某个状态
(1)执行父组件render阶段的生命周期钩子:getDerivedStateFromProps、shouldComponentUp
date、render
(2)执行B子组件render阶段的生命周期钩子:getDerivedStateFromProps、shouldComponent
Update、render
(3)执行C子组件render阶段的生命周期钩子:getDerivedStateFromProps、shouldComponent
Update、render
(4)执行B子组件的getSnapshotBeforeUpdate
(5)执行C子组件的getSnapshotBeforeUpdate
(6)执行A父组件的getSnapshotBeforeUpdate
(7)执行B子组件的componentDidUpdate
(8)执行C子组件的componentDidUpdate
(9)执行A父组件的componentDidUpdate
说明:父组件某状态的改变,会将父组件和其所有子组件的部分生命周期钩子都触发执行一遍