реагируйте на собственный recyclerlistview, если состояние изменило прокрутку на верхнее

#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, но если я что-нибудь введу в поле ввода, оно автоматически сфокусируется. Почему? Я редактирую приведенный выше код плоского списка