#javascript #reactjs #react-native #memoization
Вопрос:
Основная проблема
Мой плоский список игнорирует детские воспоминания.
Объяснение
Я реализовал пользовательский компонент «Сетка», который просто отображает данные в плоском списке с макетом сетки.
Вот код:
export default function Grid({ data = [], keyExtractor, numColumns = 4, initialNumToRender, renderItem, itemMargin = StyleSheet.hairlineWidth, isLoading, onEndReachedThreshold = 0.5, onEndReached, ...props }) { const renderGridItem = (item) =gt; { const { index } = item; const { width } = Dimensions.get("window"); const size = Math.floor( PixelRatio.roundToNearestPixel( (width - itemMargin * (numColumns - 1)) / numColumns ) ); // We don't want to include a `marginLeft` on the first item of a row const marginLeft = index % numColumns === 0 ? 0 : itemMargin; // We don't want to include a `marginTop` on the first row of the grid const marginTop = index lt; numColumns ? 0 : itemMargin; return renderItem({ ...item, size, marginLeft, marginTop, }); }; const renderFooter = () =gt; { if (!isLoading) return null; return ( lt;View style={globalStyles.listFooter}gt; lt;Loading /gt; lt;/Viewgt; ); }; return ( lt;FlatList {...props} data={data} keyExtractor={keyExtractor} numColumns={numColumns} initialNumToRender={initialNumToRender} renderItem={renderGridItem} ListFooterComponent={renderFooter} onEndReachedThreshold={onEndReachedThreshold} onEndReached={onEndReached} style={globalStyles.listContainer} contentContainerStyle={globalStyles.listContainer} /gt; ); }
Кроме того, у меня есть компонент верхнего уровня, который просто отображает мой запомненный компонент внутри моего пользовательского компонента сетки, используя пользовательскую функцию renderItem:
export default function UserPostsGrid({ listKey, data = [], numColumns, initialNumToRender, itemMargin, isLoading, ListEmptyComponent, onEndReached, ...props }) { const keyExtractor = useCallback(({ id }) =gt; id, []); const renderItem = useCallback( ({ item, index, size, marginLeft, marginTop }) =gt; { const style = { width: size, height: size, marginLeft, marginTop, }; return lt;UserPostsGridItem item={item} index={index} style={style} /gt;; }, [] ); return ( lt;Grid {...props} listKey={listKey} data={data} keyExtractor={keyExtractor} numColumns={numColumns} renderItem={renderItem} initialNumToRender={initialNumToRender} isLoading={isLoading} removeClippedSubviews={false} ListEmptyComponent={ListEmptyComponent} itemMargin={itemMargin} onEndReachedThreshold={0.5} onEndReached={onEndReached} /gt; ); }
The thing is, that for some reason, my memoized components which are returned from the renderItem function, are magically re-rendered when the data prop changes.
For example, if I add a new element to my current data list, the FlatList will re-render all of its items.
Here is my memoized component:
function UserPostsGridItem({ item: { index, images: [{ uri, thumbnailUri }], }, style, }) { const handleOnPress = () =gt; { // TODO - Push card lists stack console.log(index); }; console.log("Rerendering grid item!", uri); return ( lt;TouchableOpacity activeOpacity={0.5} onPress={handleOnPress} style={style}gt; lt;Image uri={uri} thumbnailUri={thumbnailUri} imageFadeDuration={200} thumbnailFadeDuration={100} withLoading={false} style={globalStyles.flexContainer} /gt; lt;/TouchableOpacitygt; ); } function areUserPostsGridItemPropsEqual() { console.log("Running areEqual"); // lt;---- NOTE THIS! return true; } export default memo(UserPostsGridItem, areUserPostsGridItemPropsEqual);
Как вы можете видеть, мой метод AreEqual возвращает значение true, поэтому я предполагаю, что ошибка в одном из родительских компонентов (Grid или UserPostsGrid).
Есть какие-нибудь идеи о том, что я делаю не так?
Примечание
После изменения реквизита данных (состояние в родительском) из
data=[{id: "1", ...}]
Для
data=[{id: "2", ...}, {id: "1", ...}]
Я получаю это в консоли:
"Rerendering grid item! uri..." "Rerendering grid item! uri..."
ФУНКЦИЯ ARE EQUAL НЕ ВЫПОЛНЯЕТСЯ!!!!!!
Ответ №1:
Хорошо, проблема в том, что numColumns gt; 1.
Из-за виртуализации мои компоненты монтируются заново, а не повторно визуализируются.