Как использовать callBack () Хуки с FlatList? - PullRequest
0 голосов
/ 05 апреля 2020

Я пытаюсь улучшить производительность своего приложения, поэтому я использую F C для рендеринга элементов,

, но у меня это не работает!

при прокрутке до вниз i ++ page

и в useEffect () я отправляю запрос, чтобы получить новые данные, основанные на работе страницы, и хорошо отобразить элемент в пользовательском интерфейсе! "load More feature".

Но когда я записываю весь массив "song" перед тем, как щелкнуть по элементу, я просто получаю первые две страницы! и иногда я получаю пустой массив.

Так что же не так в моем коде здесь?

const LastSongs = (props) => {
  const [songs, setSongs] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const [page, setPage] = React.useState(1);
  const [last_page, setLast_page] = React.useState(1);

  const {saveSongs, isPlaying, isPauseTrigger} = props;

  const _renderItems = useCallback(
    // the same reference with each rerender
    ({item, index}) => (
      <TouchableNativeFeed
        key={item.id}
        onPress={() => {
          console.log('onPress', songs);
          saveSongs(songs, index);
          isPlaying(true);
          isPauseTrigger(!isPauseTrigger);
        }}
        background={TouchableNativeFeedback.Ripple('white')}
        delayPressIn={0}
        useForeground>
        <Card
          style={{
            justifyContent: 'center',
            alignItems: 'center',
            backgroundColor: '#121212',
            flex: 1,
          }}>
          <FastImage
            source={{uri: item.img}}
            resizeMode={FastImage.resizeMode.cover}
            style={styles.cardImg}
          />
          <Body style={{...styles.cardItem, width: '100%'}}>
            <View style={styles.radioCardName}>
              <Text style={styles.text} numberOfLines={1}>
                {item.name}
              </Text>
            </View>
          </Body>
        </Card>
      </TouchableNativeFeed>
    ),
    [saveSongs, isPlaying, isPauseTrigger],
  );

  const renderFooter = useCallback(
    // the same reference with each rerender
    () => {
      return loading ? (
        <View style={styles.loader}>
          <ActivityIndicator size="large" />
        </View>
      ) : null;
    },
    [loading],
  );

  const handleLoadMore = useCallback(
    // the same reference with each rerender
    () => {
      if (page <= last_page - 1) {
        setPage(page + 1);
      }
    },
    [page, last_page],
  );

  React.useEffect(() => {
    let isCancelled = false;
    setLoading(true);

    const getData = async () => {
      let response = await API.get(`/tracks?page=${page}`);
      let lastPage = response.data.data.items.last_page;
      setLast_page(lastPage);
      let {
        data: {
          data: {
            items: {data},
          },
        },
      } = response;
      let All_Songs = [];
      data.map((track) =>
        All_Songs.push({
          id: track.id,
          name: track.name,
          url: URL + track.sounds,
          img: URL + track.avatar,
        }),
      );
      setSongs(songs.concat(All_Songs));
      setLoading(false);
    };
    getData();
    console.log('songs', songs);
  }, [page]);

  return (
    <Container style={styles.container}>
      <Header
        style={styles.darkHeader}
        androidStatusBarColor="#121212"
        iosBarStyle="light-content">
        <Left>
          <Button transparent onPress={() => props.navigation.goBack()}>
            <Icon name="ios-arrow-forward" style={styles.colorWhite} />
          </Button>
        </Left>
        <Body>
          <Title style={styles.headerText}>last songs</Title>
        </Body>
        <Right></Right>
      </Header>
      <FlatList
        data={songs}
        keyExtractor={_keyExtractor} // the same reference with each rerender
        initialNumToRender={10}
        contentContainerStyle={styles.contentContainerStyle} // the same reference with each rerender
        columnWrapperStyle={styles.columnWrapperStyle} // the same reference with each rerender
        numColumns={2}
        ListEmptyComponent={_renderListEmptyComponent} // the same reference with each rerender
        renderItem={_renderItems}
        onEndReached={handleLoadMore}
        onEndReachedThreshold={100}
        ListFooterComponent={renderFooter}
        removeClippedSubviews={true}
        maxToRenderPerBatch={1} // Reduce number in each render batch
        maxToRenderPerBatch={100} // Increase time between renders
        windowSize={7}
      />
    </Container>
  );
};

const _keyExtractor = (song) => song.id;

const _renderListEmptyComponent = () => <EmptyList />;

const mapDispatchToProps = (dispatch) => {
  return {
    isPlaying: (_isPlaying) => {
      dispatch(isPlayingAction(_isPlaying));
    },

    isPauseTrigger: (_isPause) => {
      dispatch(isPauseAction(_isPause));
    },

    saveSongs: (songs, index) => {
      dispatch(saveSongsPlayer(songs, index));
    },
  };
};

export default connect(null, mapDispatchToProps)(LastSongs);

1 Ответ

0 голосов
/ 05 апреля 2020

Попробуйте изменить массив зависимостей на _renderItems, чтобы включить песни. Измените его на: [saveSongs, isPlaying, isPauseTrigger, songs]. Таким образом, замыкание в callBack всегда будет включать в себя самые последние песни.

Я бы настоятельно рекомендовал использовать параметры реакции-крючков. Они значительно помогут вам убедиться, что вы не упускаете ничего в своих массивах зависимостей. https://www.npmjs.com/package/eslint-plugin-react-hooks

Если после добавления песен в массив зависимостей в списке возникла проблема, вы можете попробовать:

const songsRef = useRef(songs);
useEffect(() => {
  songsRef.current = songs;
}, [songs]);

И затем используйте songRef.current вместо песен в функции _renderItems

Обновление из чата:

Хорошо, исправлено бесконечное l oop: Экспо-закуска

Причина, по которой был бесконечный l oop, заключалась в том, что у вас были песни в массиве зависимостей useEffect. Это означало, что каждый раз, когда useEffect добавлялся к массиву песен, useEffect срабатывало повторно.

Я исправлял это, удаляя песни из массива, а затем используя метод обратного вызова useState для установки состояния: setSongs (songs => songs.concat (all_songs));

...