关于react rerendering和mount/unmount我有这个问题。如果我们在另一个父功能组件中定义了一个组件,并且父组件的状态发生了变化,很明显父组件将重新呈现。
问题:但是,在它内部定义的子功能组件是否也会重新渲染,或者它会卸载然后再次挂载?
我使用下面的代码作为这个问题的参考。下面代码的问题是,当用户输入时,每次击键后焦点都会丢失(或者在react-native的情况下键盘会消失),作者给出的原因是当Form函数重新呈现时,子函数会重新声明。但我不确定它的意思是重新声明,这意味着它得到重新渲染或得到卸载,并得到再次挂载?根据作者的说法,解决这个问题的方法是传递{Input()}或在父窗体组件之外定义子组件。这是原始文章https://levelup.gitconnected.com/code-review-avoid-declaring-react-component-inside-parent-component-1768a645f523的链接
import { useState } from 'react';
const Form = () => {
const [values, setValues] = useState(['', '']);
const onChange = (value, index) => {
const newValues = [...values];
newValues[index] = value;
setValues(newValues);
};
const Input = (props) => {
return <input type='text' {...props} />;
};
return (
<>
{values.map((value, index) => (
<Input
key={index}
value={value}
onChange={(e) => onChange(e.target.value, index)}
/>
))}
<button onClick={() => setValues([...values, ''])}>Add</button>
</>
);
};
3条答案
按热度按时间gxwragnw1#
在React中,当父组件经历重新渲染时,其子组件也会自动重新渲染。在所提供的代码示例中,子组件“Input”在父组件“Form”内定义。因此,每当“Form”被重新渲染时,“Input”的新示例被创建。
这意味着当状态改变触发“表单”组件的重新渲染时,“输入”组件也经历重新渲染。但是,由于每次重新呈现“Form”时都会生成“Input”的新示例,因此将卸载“Input”的先前示例,并安装新示例以替换它。
这可能会导致一些问题,比如每次击键时键盘都会消失,因为新安装的“Input”示例不会保持与前一个示例相同的焦点状态。为了避免这样的问题,可以在“Form”组件之外定义“Input”组件,这允许在“Form”的每次重新渲染上重用“Input”的相同示例。
总结一下,默认情况下,当父组件在React中重新渲染时,其子组件也会重新渲染。但是,如果在父组件内部定义了子组件,则在每次重新呈现父组件时都会重新声明它,这会导致旧示例被卸载,新示例被挂载到它的位置
bq3bfh9z2#
要理解这一点,您必须了解reconciliation算法。
当在一个render react中看到树层次结构中的某个组件时,说:
然后在下一个渲染中,它会看到一个不同的组件:
在树层次结构中的相同位置,卸载
ComponentA
,并挂载ComponentB
。现在,当你在另一个组件内部定义一个组件时,当外部组件重新渲染时,内部组件函数(用于创建组件的函数)重新创建,react会认为它是不同的组件类型(因为函数引用现在不同了)。因此,我们得到与
ComponentA
和ComponentB
类似的情况。这就是为什么组件必须在外部定义的原因。当它在外部定义时,用于创建组件的函数在重新渲染之间保持不变(引用也不会改变)。在这种情况下,重新渲染父对象将简单地导致子对象重新渲染,而无需卸载。
js81xvg63#
子组件(Input)在父组件(Form)内部定义。每次父组件重新呈现时,子组件(Input)的函数都将重新声明。这意味着子组件将被重新安装,这意味着在父组件的每次重新渲染中,子组件都是一个新功能。这就是为什么每次按下键时焦点都会丢失。