Как использовать ScrollToIndex в React Native? - PullRequest
0 голосов
/ 27 апреля 2020

Я использую FlatList для отображения результатов поиска.

    <View>
      <FlatList
        data={this.state.films}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({item}) => <FilmItem film={item}/>}
      />
    </View>

Однако, когда пользователь начинает второй поиск, этот список не перезапускается до индекса 0. Поэтому я хотел бы добавить ScrollToIndex или viewPosition. Я пробовал это, но это не работает:

   <View>
      <FlatList
        data={this.state.films}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({item}) => <FilmItem film={item}/>}
        scrollToItem={(index) => {0}}
      />
    </View>

Не могли бы вы объяснить мне, почему это неправильно и что было бы лучшим решением?

Большое спасибо,

Ответы [ 3 ]

1 голос
/ 28 апреля 2020

Попробуйте это ... Я сделал кучу изменений и добавил комментарии:

// Components/Search.js

import React from "react";
import {StyleSheet, View, TextInput, Button, Text, FlatList, ActivityIndicator} from "react-native";
import FilmItem from "./filmItem";
import {getFilmsFromApiWithSearchedText} from "../API/TMDBApi";

class Search extends React.Component {
  flatListRef = null; // declaring this here to make it explicit that we have this available

  constructor(props) {
    super(props);
    this.searchedText = "";
    this.state = {
      films: [],
      isLoading: false,
    };
  }

  _loadFilms = () => {
    // needs to be an arrow function so `this` is bound to this component

    this.scrollToIndex(); // assumed you meant to actually call this?

    if (this.searchedText.length > 0) {
      this.setState({isLoading: true});
      getFilmsFromApiWithSearchedText(this.searchedText).then(data => {
        this.setState({
          films: data.results,
          isLoading: false,
        });
      });
    }
  };

  // needs arrow to use `this`
  _searchTextInputChanged = text => {
    this.searchedText = text;
  };

  // needs arrow to use `this`
  _displayLoading = () => {
    // better to return null if not loading, otherwise return loading indicator
    if (!this.state.isLoading) return null;

    return (
      <View style={styles.loading_container}>
        <ActivityIndicator size='large' />
      </View>
    );
  };

  scrollToIndex = () => {
    // you previously had this inside another method
    this.flatListRef && this.flatListRef.scrollToIndex({index: 1}); // checking it exists first
  };

  render() {
    return (
      <View style={styles.main_container}>
        <TextInput
          style={styles.textinput}
          placeholder='Titre du film'
          onChangeText={text => this._searchTextInputChanged(text)}
          onSubmitEditing={this._loadFilms} // no need to create a new anonymous function here
        />

        <Button title='Rechercher' onPress={this._loadFilms} />

        <View>
          <FlatList
            data={this.state.films}
            ref={ref => (this.flatListRef = ref)}
            keyExtractor={item => item.id.toString()}
            onEndReachedThreshold={1} // corrected typo
            onEndReached={() => {
              console.log("TOC");
            }}
            renderItem={({item}) => <FilmItem film={item} />}
          />
        </View>
        {this._displayLoading()}
      </View>
    );
  }
}

const styles = StyleSheet.create({
  main_container: {
    marginTop: 60,
    padding: 15,
    flex: 1,
  },

  loading_container: {
    position: "absolute",
    left: 0,
    right: 0,
    top: 100,
    bottom: 0,
    alignItems: "center",
    paddingTop: 50,
    backgroundColor: "white",
  },

  textinput: {
    height: 50,
    borderColor: "#999999",
    borderWidth: 1,
    paddingLeft: 5,
  },
});

export default Search;
0 голосов
/ 28 апреля 2020

Я пытался добавить ссылку, но она не работает:

// Components/Search.js

import React from 'react'
import { StyleSheet, View, TextInput, Button, Text, FlatList, ActivityIndicator } from 'react-native'
import FilmItem from './filmItem'
import { getFilmsFromApiWithSearchedText } from '../API/TMDBApi'

class Search extends React.Component {

  constructor(props) {
      super(props)
      this.searchedText = ""
      this.state = {
        films: [],
        isLoading: false,
      }
  }

  _loadFilms() {
    {this.scrollToIndex}
    if (this.searchedText.length > 0) {
      this.setState({isLoading: true})
      getFilmsFromApiWithSearchedText(this.searchedText).then(data => {
          this.setState({
            films: data.results,
            isLoading: false
          })
      })

    }
  }

  _searchTextInputChanged(text) {
    this.searchedText = text
  }

  _displayLoading() {
  if (this.state.isLoading) {
    return (
      <View style={styles.loading_container}>
        <ActivityIndicator size='large'/>
      </View>
    )
    }

    scrollToIndex = () => {
    this.flatListRef.scrollToIndex({index: 1});
    }
}

  render() {
    return (
      <View style={styles.main_container}>
        <TextInput
          style={styles.textinput}
          placeholder='Titre du film'
          onChangeText={(text) => this._searchTextInputChanged(text)}
          onSubmitEditing={() => this._loadFilms()}
        />

        <Button title='Rechercher' onPress={() => this._loadFilms()} />

        <View>
          <FlatList
            data={this.state.films}
            ref={(ref) => { this.flatListRef = ref; }}
            keyExtractor={(item) => item.id.toString()}
            onEndReachedThreashold={1}
            onEndReached={() => {console.log("TOC")}}
            renderItem={({item}) => <FilmItem film={item}/>}
          />
        </View>
      {this._displayLoading()}
      </View>
    )
  }
}

const styles = StyleSheet.create({
  main_container: {
    marginTop: 60,
    padding: 15,
    flex: 1,
  },

  loading_container: {
  position: 'absolute',
  left: 0,
  right: 0,
  top: 100,
  bottom: 0,
  alignItems: 'center',
  paddingTop: 50,
  backgroundColor: 'white',
},

  textinput: {
    height: 50,
    borderColor: '#999999',
    borderWidth: 1,
    paddingLeft: 5,
  }
})

export default Search

Я не уверен, что делаю что-то не так, но не могу найти ошибку. Большое спасибо за вашу помощь.

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

Используя этот код в качестве примера:

import React, { Component } from 'react';
import { Text, View, FlatList, Dimensions, Button, StyleSheet } from 'react-native';

const { width } = Dimensions.get('window');

const style = {
  justifyContent: 'center',
  alignItems: 'center',
  width: width,
  height: 50,
  flex: 1,
  borderWidth: 1,
};

const COLORS = ['deepskyblue','fuchsia', 'lightblue '];

function getData(number) {
  let data = [];
  for(var i=0; i<number; ++i)
  {
    data.push("" + i);
  }

  return data;
}

class ScrollToExample extends Component {

  getItemLayout = (data, index) => (
    { length: 50, offset: 50 * index, index }
  )

  getColor(index) {
    const mod = index%3;
    return COLORS[mod];
  }

  scrollToIndex = () => {
    let randomIndex = Math.floor(Math.random(Date.now()) * this.props.data.length);
    this.flatListRef.scrollToIndex({animated: true, index: randomIndex});
  }

  scrollToItem = () => {
    let randomIndex = Math.floor(Math.random(Date.now()) * this.props.data.length);
    this.flatListRef.scrollToIndex({animated: true, index: "" + randomIndex});
  }

  render() {
    return (
      <View style={styles.container}>
        <View style={styles.header}>
          <Button
            onPress={this.scrollToIndex}
            title="Tap to scrollToIndex"
            color="darkblue"
          />
          <Button
            onPress={this.scrollToItem}
            title="Tap to scrollToItem"
            color="purple"
          />
        </View>
        <FlatList
          style={{ flex: 1 }}
          ref={(ref) => { this.flatListRef = ref; }}
          keyExtractor={item => item}
          getItemLayout={this.getItemLayout}
          initialScrollIndex={50}
          initialNumToRender={2}
          renderItem={({ item, index}) => (
              <View style={{...style, backgroundColor: this.getColor(index)}}>
                <Text>{item}</Text>
              </View>
            )}
          {...this.props}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1
  },
  header: {
    paddingTop: 20,
    backgroundColor: 'darkturquoise', 
    alignItems: 'center', 
    justifyContent: 'center'
  }
});

export default class app extends Component {
  render() {
    return  <ScrollToExample
              data={getData(100)}
            />
  }
}

...