FlatList ref scrollToIndex不是函数

时间:2019-12-13 06:50:55

标签: react-native animation reference undefined react-native-flatlist

我面对的是React Native中一个长期存在的问题。
我正在使用带有RN版本0.59的Expo SDK35。由于代码量很大,我还没有更新到Expo SDK36 / RN 0.60,但是如果可以弥补我的问题,我可以更新。

我有一个Animated.View子组件,它有一个FlatList子组件,并且我无法使用FlatList引用上应该可用的静态方法(尤其是scrollToIndex())。请参见下一个示例代码:

class Example extends React.Component{
    constructor(props){
        super(props);
        this.myRef = null;
    }

    componentDidUpdate = () => {
        /*
            somewhere in code outside this class, a re-render triggers
            and passes new props to this class.
            I do have props change detection, and some more other code,
            but I have removed it in order to minimize the code example here
        */

        // This call throws:
        // TypeError: undefined is not a function (near '...this._scrollRef.scrollTo...')
        this.myRef.scrollToIndex({
            animated: true,
            index: 1,
            viewOffset: 0,
            viewPosition: 0.5
        });

        // Other suggested solution from SO
        // This also throws:
        // TypeError: _this.myRef.getNode is not a function. (In '_this.myRef.getNode()', '_this.myRef.getNode' is undefined)
        this.myRef.getNode().scrollToIndex({
            animated: true,
            index: 1,
            viewOffset: 0,
            viewPosition: 0.5
        });
    }
    render = () => <Animated.View style={{ /* ... some animated props */ }}>
        <FlatList ref={(flatListRef) => { this.myRef = flatListRef; }}
            // more FlatList related props
        />
    </Animated.View>
}

我尝试改用Animated.FlatList,但仍然引发与上面的代码示例相同的错误。
我还尝试在接收到的findNodeHandle()参数上使用react native的flatListRef实用程序功能,但它返回null

我发现过去在此处的Stack Overflow上多次发布了相同的问题,大多数问题没有答案,或者对我不起作用。这些帖子也有点旧(一年左右),这就是为什么我针对同一问题再次发布。

有人设法找到此问题的解决方案/解决方法吗?

编辑:可能的解决方法

在玩代码时,我尝试使用ScrollView组件而不是FlatList-并且scrollTo方法有效!
所做的更改仅在FlatList-ScrollView特定的道具上(因此,对于ScrolLView,它将是孩子,而不是data={[...]}renderItem={()=>{ ... }}等),以及componentDidMount中的scrollToIndex方法被scrollTo取代。
带有ScrollView的类的render方法现在看起来像这样:

    render = () => <Animated.View style={{ /* ... some animated props */ }}>
        <ScrollView ref={(flatListRef) => { this.myRef = flatListRef; }}>
            {/*
                this.renderItem is almost the same as the
                renderItem method used on the FlatList
             */}
             { this.state.dataArray.map(this.renderItem) }
        </ScrollView>
    </Animated.View>

请注意,ScrollView没有scrollToIndex()方法,因此您必须手动跟踪子位置,并可能实现自己的scrollToIndex方法。

我并没有将这个问题作为答案,因为根本的问题仍然存在。但是,作为一种解决方法,也许您可​​以将其命名为“一天” ...

4 个答案:

答案 0 :(得分:2)

TL; DR;


this.myRef = React.createRef();
this.myRef.current.doSomething(); // note the use of 'current'

长版:

虽然我尝试的想法背后的想法是正确的,但我最初帖子中的错误似乎非常愚蠢。在我的辩护中,文档不清楚(可能是...)。反正...

React.createRef返回一个带有几个字段的对象,所有这些字段对开发人员都无用(后面由React使用)-除了一个current。 该属性将保持对引用附加到的基础组件的当前引用。主要的ref对象无法用于我在上面的原始问题中想要达到的目的。

相反,这就是我应该正确使用ref的方式:

this.myRef.current.scrollToIndex(...)

举起手来,不要崩溃

主要myRef对象和current字段都将是null,如果该组件尚未安装,在以后的任何时候已卸载或无法连接引用由于某种原因。您可能知道(或以后发现),null.something将引发错误。因此,为避免这种情况:

if ((this.myRef !== null) && (this.myRef.current !== null)){
    this.myRef.current.scrollToIndex(...);
}

额外保险

如果您尝试在ref的字段上调用未定义的值作为函数,则代码将崩溃。如果您错误地在多个组件上重用了相同的ref,或者如果附加了该组件的组件没有该方法(即View没有scrollTo方法),则会发生这种情况。要解决此问题,您有两种解决方案:

// I find this to be the most elegant solution
if ((this.myRef !== null) && (this.myRef.current !== null)) {
    if (typeof this.myRef.current.scrollToIndex === "function") {
        this.myRef.current.scrollToIndex(...);
    }
}

if ((this.myRef !== null) && (this.myRef.current !== null)) {
    if (typeof this.myRef.current.scrollToIndex === "function") {
        try {
            this.myRef.current.scrollToIndex(...);
        } catch (error) {
            console.warn("Something went wrong", error);
        }
    }
}

我希望这对其他在React中使用refs的人有用。干杯:)

答案 1 :(得分:0)

使用Animated.ScrollView

  • 创建对FlatList的引用(仅适用于旧方法)

<ScrollView ref={ (ref) => (this.MyRef=ref) } />

  • 使用scrollToIndex访问this.myRef.getNode().scrollToIndex

Animated.FlatList当前无法正常工作...

使用FlatList

  • 通过以下方式创建对您的FlatList的引用:

<FlatList ref={ this.flatListRef } />

  constructor(props) {
    super(props);

    this.flatListRef = React.createRef();
  }
  • 使用scrollToIndex访问this.flatListRef.current.scrollToIndex

还要确保将代码包装在if语句中,例如:

 if (this.myRef.getNode()) { this.flatListRef.getNode().scrollToIndex(); }

答案 2 :(得分:0)

o不知道这是否对您有帮助...它滚动到列表中的一个特定项目:

/*Example to Scroll to a specific position in scrollview*/
import React, { Component } from 'react';
//import react in our project

import {
  View,
  ScrollView,
  StyleSheet,
  Text,
  TouchableOpacity,
  Image,
  TextInput,
} from 'react-native';
//import all the components we needed

export default class App extends Component {
  constructor() {
    super();
    //Array of Item to add in Scrollview
    this.items = [
      'zero',
      'one',
      'two',
      'three',
      'four',
      'five',
      'six',
      'seven',
      'eight',
      'nine',
      'ten ',
      'eleven',
      'twelve',
      'thirteen',
      'fourteen',
      'fifteen',
      'sixteen',
      'seventeen',
      'eighteen',
      'nineteen',
      'twenty ',
      'twenty-one',
      'twenty-two',
      'twenty-three',
      'twenty-four',
      'twenty-five',
      'twenty-six',
      'twenty-seven',
      'twenty-eight',
      'twenty-nine',
      'thirty',
      'thirty-one',
      'thirty-two',
      'thirty-three',
      'thirty-four',
      'thirty-five',
      'thirty-six',
      'thirty-seven',
      'thirty-eight',
      'thirty-nine',
      'forty',
    ];
    //Blank array to store the location of each item
    this.arr = [];
    this.state = { dynamicIndex: 0 };
  }
  downButtonHandler = () => {
    if (this.arr.length >= this.state.dynamicIndex) {
      // To Scroll to the index 5 element
      this.scrollview_ref.scrollTo({
        x: 0,
        y: this.arr[this.state.dynamicIndex],
        animated: true,
      });
    } else {
      alert('Out of Max Index');
    }
  };
  render() {
    return (
      <View style={styles.container}>
        <View
          style={{
            flexDirection: 'row',
            backgroundColor: '#1e73be',
            padding: 5,
          }}>
          <TextInput
            value={String(this.state.dynamicIndex)}
            numericvalue
            keyboardType={'numeric'}
            onChangeText={dynamicIndex => this.setState({ dynamicIndex })}
            placeholder={'Enter the index to scroll'}
            style={{ flex: 1, backgroundColor: 'white', padding: 10 }}
          />
          <TouchableOpacity
            activeOpacity={0.5}
            onPress={this.downButtonHandler}
            style={{ padding: 15, backgroundColor: '#f4801e' }}>
            <Text style={{ color: '#fff' }}>Go to Index</Text>
          </TouchableOpacity>
        </View>
        <ScrollView
          ref={ref => {
            this.scrollview_ref = ref;
          }}>
          {/*Loop of JS which is like foreach loop*/}
          {this.items.map((item, key) => (
            //key is the index of the array
            //item is the single item of the array
            <View
              key={key}
              style={styles.item}
              onLayout={event => {
                const layout = event.nativeEvent.layout;
                this.arr[key] = layout.y;
                console.log('height:', layout.height);
                console.log('width:', layout.width);
                console.log('x:', layout.x);
                console.log('y:', layout.y);
              }}>
              <Text style={styles.text}>
                {key}. {item}
              </Text>
              <View style={styles.separator} />
            </View>
          ))}
        </ScrollView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 30,
  },
  separator: {
    height: 1,
    backgroundColor: '#707080',
    width: '100%',
  },

  text: {
    fontSize: 16,
    color: '#606070',
    padding: 10,
  },
});

如果我完全错了,告诉我...

答案 3 :(得分:0)

因为ScrollView没有scrollToOffset功能,而只有scrollTo功能。

因此,让功能scrollTo与ScrollView一起使用,或者scrollToOffset与FlatList一起使用,它可以正常工作。