[英]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.