FlatList refscrollToIndex 不是一个函数

cri*_*ian 7 animation reference undefined react-native react-native-flatlist

我面临着 React Native 中似乎长期存在的问题。
我正在使用带有 RN 版本 0.59 的 Expo SDK35。由于代码库较大,我尚未更新到 Expo SDK36 / RN 0.60,但如果这可以弥补我的问题的解决方案,我可以更新。

我有一个Animated.ViewFlatList子组件的组件,并且我无法使用scrollToIndex()FlatList 引用上应该提供的静态方法(特别是)。请参阅下一个示例代码:

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>
}
Run Code Online (Sandbox Code Playgroud)

我尝试使用Animated.FlatList它,但仍然抛出与上面的代码示例中相同的错误。
我还尝试findNodeHandle()在接收到的参数上使用 React Native 的实用函数flatListRef,但它返回null.

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

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

编辑:可能的解决方法

当我玩代码时,我尝试使用ScrollView组件而不是FlatList- 并且该scrollTo方法有效!
更改仅针对 FlatList - ScrollView 特定道具(因此,对于 ScrollLView 来说,它将是子级而不是data={[...]}renderItem={()=>{ ... }}等),以及scrollToIndexcomponentDidMount 中的方法被替换为scrollTo
该类的 render 方法(带有 ScrollView)现在如下所示:

    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>
Run Code Online (Sandbox Code Playgroud)

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

我不会将此作为我问题的答案,因为根本问题仍然存在。但作为一种解决方法,也许你可以接受它,然后就到此为止......

cri*_*ian 8

TL;博士;


this.myRef = React.createRef();
this.myRef.current.doSomething(); // note the use of 'current'
Run Code Online (Sandbox Code Playgroud)

长版:

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

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

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

this.myRef.current.scrollToIndex(...)
Run Code Online (Sandbox Code Playgroud)

坚持住,别摔坏

myRef如果组件尚未安装、稍后已卸载,或者由于某种原因无法将引用附加到它,则主对象和字段都将是currentnull正如您可能知道的(或稍后发现的),null.something会抛出错误。因此,为了避免它:

if ((this.myRef !== null) && (this.myRef.current !== null)){
    this.myRef.current.scrollToIndex(...);
}
Run Code Online (Sandbox Code Playgroud)

额外保险

如果您尝试将未定义的值作为函数调用 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(...);
    }
}
Run Code Online (Sandbox Code Playgroud)

或者

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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