摘要
本文探讨 React 的协调算法,包括组件的条件渲染、'key'属性的使用、组件内部声明组件的问题等,通过示例解释不同渲染条件下组件的挂载和重新挂载行为。
React 组件的条件渲染
React 中的组件条件渲染会影响组件的挂载和重新挂载。例如在一个注册表单中,根据用户是否选择为公司来决定显示不同的输入框。
const Form = () => {
const [isCompany, setIsCompany] = useState(false);
return (
<>
{isCompany? (
<Input id="company - tax - id - number" placeholder="Enter you company ID"... />
) : (
<TextPlaceholder />
)}
</>
);
}
这里,如果isCompany
的值改变,组件会重新渲染,相应的组件会挂载或卸载。
相同类型组件的渲染
当条件渲染中的组件类型相同时,React 会重新渲染而不是重新挂载组件。
const Form = () => {
const [isCompany, setIsCompany] = useState(false);
return (
<>
{isCompany? (
<Input id="company - tax - id - number" placeholder="Enter you company Tax ID"... />
) : (
<Input id="person - tax - id - number" placeholder="Enter you personal Tax ID"... />
)}
</>
);
}
在这种情况下,输入框组件的类型都是Input
,React 只会更新组件的属性,而不是重新挂载组件。
React 的协调算法
协调算法的目的
协调算法是因为 DOM 操作的缓慢而存在的。React 通过创建和修改虚拟 DOM 来处理组件的渲染。虚拟 DOM 是一个包含所有要渲染的组件、组件属性和子组件的大型对象。
组件挂载过程
当 React 进行初始渲染时,它会遍历虚拟 DOM 树。如果节点的type
是字符串,就生成对应的 HTML 元素;如果type
是函数(即组件),就调用该函数并遍历其返回的树,直到得到整个 DOM 节点树并显示在屏幕上。
组件的重新渲染和状态更新
状态更新时的比较
当组件的状态更新触发重新渲染时,React 会比较更新前后组件的type
字段。如果type
相同,组件会被标记为需要更新并重新渲染;如果type
改变,React 会卸载旧组件并挂载新组件。
const Component = () => {
return <Input />;
};
在这个例子中,如果Component
返回的Input
组件的type
没有改变,就会重新渲染。
条件渲染中的类型改变
如果在条件渲染中组件的类型发生改变,React 会卸载旧组件并挂载新组件。
const Component = () => {
if (isCompany) return <Input />;
return <TextPlaceholder />;
};
这里,如果isCompany
的值改变,Component
返回的组件类型会改变,React 会相应地进行挂载和卸载操作。
数组与协调算法
数组中的元素比较
在 React 组件中,数组元素的渲染在重新渲染时,React 会根据元素在数组中的位置比较前后的元素和它们的type
。
const Form = () => {
const [isCompany, setIsCompany] = useState(false);
return (
<>
<Checkbox onChange={() => setIsCompany(!isCompany)} />
{isCompany? <Input id="company - tax - id - number"... /> : null}
{!isCompany? <Input id="person - tax - id - number"... /> : null}
</>
);
}
这个表单组件中的元素在数组中的位置变化会导致不同的挂载和卸载行为。
'key'属性与协调算法
'key'属性的作用
key
属性在 React 中用于在重新渲染时识别数组中的元素。它是元素在子数组中的唯一标识符。
const data = ['1', '2'];
const Component = () => {
return data.map((value) => <Input key={value} />);
};
在动态数组中,如果没有key
属性,重新排序数组可能会导致奇怪的行为,有了key
属性,React 就能正确地复用已有的元素。
在非数组元素中的使用
即使在非数组元素中,key
属性也可以用于强制复用已有的元素。
const Component = () => {
const [isReverse, setIsReverse] = useState(false);
return (
<>
<Input key={isReverse? 'some - key' : null} />
<Input key={!isReverse? 'some - key' : null} />
</>
);
}
通过设置相同的key
值,可以让 React 认为这是同一个元素并复用它。
组件内部声明组件的问题
在组件内部声明组件是一种反模式。
const Component = () => {
const Input = () => <input />;
return <Input />;
};
因为每次父组件重新渲染时,内部声明的组件会被重新创建,导致每次重新渲染时都会重新挂载,影响性能并可能产生很多潜在的 bug。