#react-native #expo
Вопрос:
Если я изменю какое-либо состояние или изменю значение textinput, если оно изменилось, прокрутите его вверх и оставьте textinput. Или, если мне нравится один продукт, его автоматически прокручивают вверх, если массив изменен. Кто-нибудь может мне помочь ?
import React, { useState, useMemo, useEffect, forwardRef, memo } from 'react';
import { StyleSheet, Text, TextInput, View, TouchableOpacity, Image, Dimensions } from 'react-native';
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
import { RecyclerListView, LayoutProvider, DataProvider } from 'recyclerlistview';
import { useSelector, useDispatch } from 'react-redux';
import { AntDesign } from '@expo/vector-icons';
import { addAmountOnCartItem } from '../../../redux/slice/product/shopping_cart';
import faker from 'faker';
import ButtonWithoutLoader from '../../ButtonWithoutLoader';
const { width, height } = Dimensions.get('window');
const Shopping_cart_list = ({ datas, onPressSetting }) => {
const dispatch = useDispatch();
const provider = useMemo(() => {
return new DataProvider(
(r1, r2) => {
return r1 !== r2;
},
index => {
return 'id:' index;
}
)
}, []);
const dataProvider = useMemo(() => {
return provider.cloneWithRows(datas);
}, [datas, provider]);
const [update, updateRecycler] = useState({
update: false
});
const handleChange = (e, product_id) => {
dispatch(addAmountOnCartItem({ value: e, product_id }));
updateRecycler(prevState => {
return {
update: !prevState
}
});
};
const layoutProvider = new LayoutProvider((i) => {
return dataProvider.getDataForIndex(i).type;
}, (type, dim) => {
switch(type) {
case 'NORMAL':
dim.height = 250;
dim.width = width * 0.9;
break;
default:
dim.height = 0;
dim.width = 0;
break;
}
});
const RenderData = memo(({ product_id, product_name, price, product_image, amount, username }) => {
return (
<TouchableWithoutFeedback style={{height: 250, backgroundColor: '#fff', marginBottom: 16}}>
<View style={styles.header}>
<TouchableOpacity style={styles.profile_info}>
<Image source={{uri: faker.image.avatar()}} resizeMode="contain" style={styles.profile_image} />
<Text style={styles.username}>{ username }</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => onPressSetting(product_id)}>
<AntDesign name="setting" size={24} color="#444" />
</TouchableOpacity>
</View>
<View style={styles.mainContainer}>
<Image source={{uri: product_image}} style={styles.image} />
<View>
<Text style={styles.text}>{product_name}</Text>
<Text style={styles.text}>Preis: {price}</Text>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={styles.text}>Anzahl: </Text>
<AntDesign name="minussquareo" style={{marginRight: 6}} size={24} color="black" />
<TextInput onBlur={() => handleChange(1, product_id)} value={ isNaN(amount) ? '' : amount.toString() } onChangeText={e => handleChange(e, product_id)} style={{height: 28, width: 28, borderRadius: 4, textAlign: 'center', backgroundColor: '#eee'}} />
<AntDesign name="plussquareo" style={{marginLeft: 6}} size={24} color="black" />
</View>
</View>
</View>
<View style={[styles.header, { marginTop: 4 }]}>
<ButtonWithoutLoader onPress={() => updateRecycler(prevState => !prevState)} title="Jetzt Kaufen!" width={width * 0.9} />
</View>
</TouchableWithoutFeedback>
)
});
const rowRenderer = (type, data) => {
const { product_id, product_name, price, product_image, amount, username } = data.item;
return <RenderData product_id={product_id} product_name={product_name} price={price} product_image={product_image} amount={amount} username={username} />
};
return (
<View style={{flex: 1, paddingBottom: 85}}>
<RecyclerListView
dataProvider={dataProvider}
layoutProvider={layoutProvider}
forceNonDeterministicRendering={true}
rowRenderer={rowRenderer}
style={{marginLeft: width * 0.05, marginRight: width * 0.05}}
extendedState={update}
scrollViewProps={{showsVerticalScrollIndicator: false}}
/>
</View>
)
};
Плоский список:
import React, { useState, useRef, memo, useMemo } from 'react';
import { StyleSheet, Animated, FlatList, Text, TextInput, View, TouchableOpacity, Image, Dimensions } from 'react-native';
import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
import { useSelector, useDispatch } from 'react-redux';
import { useNavigation } from '@react-navigation/core';
import { AntDesign } from '@expo/vector-icons';
import { addAmountOnCartItem } from '../../../redux/slice/product/shopping_cart';
import faker from 'faker';
import ButtonWithoutLoader from '../../ButtonWithoutLoader';
const { width } = Dimensions.get('window');
const Shopping_cart = ({ datas, onPressSetting }) => {
const dispatch = useDispatch();
const navigation = useNavigation();
const [update, updateRecycler] = useState({
update: false
});
const handleChange = (e, product_id) => {
dispatch(addAmountOnCartItem({ value: e, product_id }));
updateRecycler(prevState => {
return {
update: !prevState
}
});
};
const RenderItem = memo(({ item }) => {
const { product_id, product_name, price, product_image, amount, username, size, colors, desc, selectedColor, selectedSize } = item.item;
return (
<TouchableWithoutFeedback style={{height: 300, backgroundColor: '#fff', marginBottom: 16}}>
<View style={styles.header}>
<TouchableOpacity style={styles.profile_info}>
<Image source={{uri: faker.image.avatar()}} resizeMode="contain" style={styles.profile_image} />
<Text style={styles.username}>{ username }</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => onPressSetting(product_id)}>
<AntDesign name="setting" size={24} color="#444" />
</TouchableOpacity>
</View>
<TouchableOpacity onPress={() => navigation.navigate('ProductStack', {
product_id,
desc,
price,
product_image,
username,
user_profil_image: faker.image.avatar(),
size,
colors,
})} style={styles.mainContainer}>
<Image source={{uri: product_image}} style={styles.image} />
<View>
<Text style={styles.text}>{product_name}</Text>
<Text style={styles.text}>Preis: {price}</Text>
<Text style={styles.text}>Farbe: {selectedColor}</Text>
<Text style={styles.text}>Größe: {selectedSize}</Text>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text style={styles.text}>Anzahl: </Text>
<AntDesign name="minussquareo" style={{marginRight: 6}} size={24} color="black" />
<TextInput onBlur={() => handleChange(1, product_id)} value={ isNaN(amount) ? '' : amount.toString() } onChangeText={e => handleChange(e, product_id)} style={{height: 28, width: 28, borderRadius: 4, textAlign: 'center', backgroundColor: '#eee'}} />
<AntDesign name="plussquareo" style={{marginLeft: 6}} size={24} color="black" />
</View>
</View>
</TouchableOpacity>
<View style={[styles.header, { marginTop: 4 }]}>
<ButtonWithoutLoader onPress={() => updateRecycler(prevState => !prevState)} title="Jetzt Kaufen!" width={width * 0.9} />
</View>
</TouchableWithoutFeedback>
);
});
return (
<FlatList
data={datas}
keyExtractor={item => item.item.product_id Math.random(100)}
renderItem={({ item }) => <RenderItem item={item}/>}
contentContainerStyle={{justifyContent: 'center', alignItems: 'center'}}
removeClippedSubviews={true}
initialNumToRender={2}
maxToRenderPerBatch={1}
extraData={update}
updateCellsBatchingPeriod={100}
/>
);
};
………………………………………………………………………………………………………………………………………………………………….
Ответ №1:
Если вы увидите документы RecyclerView, вы увидите для extendedState prop:
В некоторых случаях данные, передаваемые на уровне строк, могут содержать не всю информацию, от которой зависит элемент, вы можете оставить всю остальную информацию снаружи и передать ее через этот реквизит. Изменение этого объекта приведет к повторному отображению всего. Убедитесь, что вы не меняете его часто, чтобы обеспечить производительность. Повторные рендеринги очень тяжелые.
Основываясь на вашем коде, вы обновляете эту опору в обработчике нажатия кнопки и изменения текста, это в конечном итоге приведет к повторному отображению вашего экрана в соответствии с описанием. Итак, здесь вам нужно будет пересмотреть свою логику, чтобы избежать ненужных повторных рендеров.
Комментарии:
1. Привет, спасибо за ваш ответ. Я удалил расширенное состояние для теста, и оно снова отображается. Так что это не вина расширенного штата.
Ответ №2:
Недавно я только что решил эту проблему в своем собственном проекте, поэтому был бы рад помочь.
Основная проблема заключается в том, что в элементах списка не может быть состояния, связанного с пользовательским интерфейсом. Нет. Вместо этого вы должны переместить всю эту информацию, которая будет передана через реквизит.
Я вижу, что ваш единственный пример этого-через ваш текстовый ввод. Это может быть непросто. Поэтому мой первый вопрос будет таким: действительно ли вам нужен RecyclerListView? Если ваш список не состоит из тысяч элементов, а элементы имеют сложный/интенсивный пользовательский интерфейс, я бы предложил плоский список для этого проекта.
Если вам по-прежнему нужен RecyclerListView, я бы предложил сделать так, чтобы после завершения ввода текста («готово», например, после 3-секундного таймера или когда они нажимают «отправить» или что-то в этом роде) вы изменили объект данных поставщика данных. Измените элемент в нужном вам индексе, а затем повторно отправьте его с помощью cloneWithRows()
Комментарии:
1. Эй, спасибо за ваш ответ. Я думаю, что я использую flatlist вместо этого только для корзины покупок. Я не думаю, что у пользователя есть 1000 товаров в корзине :D. Но я использую recyclerlistview из-за производительности. На экране корзины покупок у меня также есть модальный, поэтому, если я использую его с flatlist и открою его, то это будет медленно. Это стало причиной выбора recyclerlistview. Но один вопрос. Как я изменяю элемент в индексе в recyclerlistview у вас есть какая-либо ссылка или ссылка для этого ?
2. Да, для корзины покупок я бы настоятельно рекомендовал плоский список. Это тоже намного проще реализовать. Единственный раз, когда мне пришлось использовать RecyclerListView для его высокой производительности, был в бесконечной ленте социальных сетей с большим количеством изображений и видео в каждом посте. Я удивлен, что вы сообщаете о чем-то медленном с модальным. Не стесняйтесь показывать свой код с помощью этого, и мы сможем увидеть, что там происходит. Простой модал не должен снижать производительность.
3. В соответствии с вашим вопросом об изменении элемента в индексе я имею в виду изменение фактического объекта «данные». Ваше хранилище данных, которое вы помещаете в » provider.cloneWithRows(данные)». Измените объект в нужном вам индексе, а затем снова сбросьте его с помощью provider.cloneWithRows(данные). Это обновит пользовательский интерфейс, даже не требуя обновления, так как все это будет проходить через реквизиты.
4. Я снова протестирую его с помощью flatlist и modal, если проблема связана с медлительностью, я опубликую код спасибо за оба ваших ответа, я очень благодарен за это
5. привет, мой друг, я использовал его с помощью flatlist, но если я что-нибудь введу в поле ввода, оно автоматически сфокусируется. Почему? Я редактирую приведенный выше код плоского списка