[英]Parent component unnecessarily re-rendering child on parent state change
我正在创建一个简单的Magic The Gathering搜索引擎。 愿景是列出搜索结果,单击搜索结果后,主显示屏将显示有关所选卡的扩展信息。
顶级App
组件包含要显示什么卡的状态,并且ScrollView
组件仅在列表中突出显示所选卡的情况下,保持所选卡的状态。 我向下传播setDisplayCard
处理程序,以便在列表中单击某个卡时,可以将显示卡设置为回调。
function App(props) {
const [displayCard, setDisplayCard] = useState(null)
return (
<div className="App">
<SearchDisplay handleCardSelect={setDisplayCard}/>
<CardDisplay card={displayCard} />
</div>
);
}
function SearchDisplay({handleCardSelect}) {
const [cards, setCards] = useState([]);
useEffect(() => {
(async () => {
const cards = await testCardSearch();
setCards(cards);
})();
}, []);
async function handleSearch(searchTerm) {
const searchCards = await cardSearch({name: searchTerm});
setCards(searchCards)
};
return (
<StyledDiv>
<SearchBar
handleSubmit={handleSearch}
/>
<ScrollView
handleCardSelect={handleCardSelect}
cards={cards}
/>
</StyledDiv>
);
}
function ScrollView({cards, handleCardSelect}) {
const [selected, setSelected] = useState(null);
return (
<ViewContainer>
{cards.map((card, idx) =>
<li
key={idx}
style={selected === idx ? {backgroundColor: "red"} : {backgroundColor: "blue"}}
onClick={() => {
setSelected(idx);
handleCardSelect(card);
}}
>
<Card card={card} />
</li>
)}
</ViewContainer>
);
}
我遇到的问题是调用setDisplayCard
重新渲染了ScrollView
并消除了所选卡的本地状态,因此我无法在列表中突出显示活动卡。 根据我对react的理解,我不明白为什么ScrollView
重新渲染,因为它不依赖于displayCard
的状态。 我不确定采取什么方法来解决它。 当我单击列表中的卡时,我希望它突出显示红色。
默认情况下(无状态)组件会在3种情况下重新渲染
可以使用shouldComponentUpdate
组件或memo
为无状态组件来更改此行为。
// If this function returns true, the component won't rerender
areEqual((prevProps, nextProps) => prevProps.cards === nextProps.card)
export default React.memo(ScrollView, areEqual);
但是我不认为这是您的问题。 您正在使用数组索引idx
作为元素键,这通常会导致意外行为。
尝试删除key={idx}
并检查是否可以解决您的问题。
一旦调用父组件的render
方法,子组件的render
方法将始终被调用。 如果道具或状态发生变化,也是如此。
由于您正在使用功能组件,因此可以使用React.memo
HOC来防止不必要的组件重新渲染。
React.memo
行为类似于PureComponent
并且将ScrollView
的旧props
与新props
进行PureComponent
比较,并且仅当它们不相等时才触发重新渲染:
export default React.memo(ScrollView);
React.memo
还有第二个参数,它使您可以控制比较:
function areEqual(prevProps, nextProps) {
// only update if a card was added or removed
return prevProps.cards.length === nextProps.cards.length;
}
export default React.memo(ScrollView, areEqual);
如果要使用基于类的组件,则也可以使用shouldComponentUpdate
生命周期方法。
因此,您的App组件应该保存用户单击的卡的状态? 现在,您的App组件是无状态的。 这是一个功能组件。 尝试将其转换为具有初始状态和维护状态的类组件。
setDisplayCard()的逻辑是什么?
我在React 16中听说过吗? 像“ useState()”和“挂钩”之类的东西,但我并不熟悉。
这个人似乎有类似的问题,
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.