FlatList ref scrollToIndex 不是函数
Posted
技术标签:
【中文标题】FlatList ref scrollToIndex 不是函数【英文标题】:FlatList ref scrollToIndex is not a function 【发布时间】:2020-04-06 14:32:05 【问题描述】:我在 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
,但仍会引发与上述代码示例相同的错误。
我还尝试在收到的flatListRef
参数上使用 react native 的 findNodeHandle()
实用函数,但它返回 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 方法。
我不会将此作为我问题的答案,因为根本问题仍然存在。但作为一种解决方法,也许你可以接受它并收工......
【问题讨论】:
【参考方案1】:TL;DR;
this.myRef = React.createRef();
this.myRef.current.doSomething(); // note the use of 'current'
长版:
虽然我尝试的想法是正确的,但我原来帖子中的错误似乎很愚蠢。在我的辩护中,文档并不清楚(可能......)。总之……
React.createRef
返回一个带有几个字段的对象,所有这些字段对开发人员都无用(由 React 在后面使用)- 除了一个:current
。
此道具保存对 ref 附加到的基础组件的当前引用。主 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 的其他人有用。干杯:)
【讨论】:
谢谢伙计。我正面临着这个,失去了三个宝贵的小时。您的解决方案修复了它。再次感谢...@克里斯蒂安【参考方案2】:使用 Animated.ScrollView:
为您的 FlatList 创建一个引用(旧方法仅适用):<ScrollView ref= (ref) => (this.MyRef=ref) />
this.myRef.getNode().scrollToIndex
访问scrollToIndex
Animated.FlatList
目前无法正常工作...
使用平面列表:
通过以下方式为您的 FlatList 创建一个引用:<FlatList ref= this.flatListRef />
constructor(props)
super(props);
this.flatListRef = React.createRef();
使用this.flatListRef.current.scrollToIndex
访问scrollToIndex
还要确保将代码包装在 if 语句中,例如:
if (this.myRef.getNode()) this.flatListRef.getNode().scrollToIndex();
【讨论】:
不幸的是,它没有用。我尝试了FlatList
和Animated.FlatList
两种方式,它总是抛出this.myRef.scrollToIndex is not a function
或this.myRef.getNode is not a function
。 :(
请按照Animated.FlatList
中的步骤...并尝试在componentDidMount
方法中使用console.log(this.flatListRef.getNode())
我确实按照您描述的步骤进行了操作,并且我还尝试了 Animated.FlatList 和 FlatList、getNode() 和直接调用参考的混合。使用 getNode() 它会在 if 语句中抛出。没有 getNode() 它会抛出引用,就像我最初描述的那样。好消息是 - 我可以改用ScrollView
。在 ScrollView 上放置一个 ref 并尝试使用与 FlatList 相同的代码(除了 renderItem、data 和其他与 FlatList 相关的道具),它可以正常工作。我不知道为什么,对我来说没有意义,但是嘿......这可能是一个解决方案......
我之前尝试过Animated.FlatList
,但它没有用......错误......问题是 -> 用 ScrollView 替换你的 FlatList 会导致性能下降(FlatList 更多优化...)
我知道性能下降,但是,我画的孩子很少(确切地说是 4 个),而且我只在需要时以编程方式滚动它们,希望不会对性能产生太大影响。但是,仍然感谢您尝试帮助我:)【参考方案3】:
不知道这是否对您有帮助...它滚动到列表中的特定项目:
/*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,
,
);
如果我完全错了,请告诉我...
【讨论】:
谢谢,不过,问题不在于如何 滚动到某个索引;问题是从这些组件的 ref 属性返回的 ScrollView 或 FlatList 引用是 无效引用,或者根本不是引用(返回 null)。因此,这使得调用任何静态 scrollTo*...* 方法成为不可能,因为没有东西可以进行调用。【参考方案4】:因为 ScrollView 没有 scrollToOffset
函数,它只有 scrollTo
函数。
所以让 scrollTo
和 ScrollView 一起使用或 scrollToOffset
和 FlatList 一起使用,它可以正常工作。
【讨论】:
这不是问题,我最初使用的是具有scrollToIndex
方法的 FlatList。我现在已经发布了我的问题的正确解决方案,请查看我上面的答案:)【参考方案5】:
如果您正在使用“KeyboardAwareFlatList”,则效果很好: https://github.com/APSL/react-native-keyboard-aware-scroll-view/issues/372
简而言之,使用 useRef 并使用KeyboardAwareFlatList
的innerRef
属性而不是ref
属性。
【讨论】:
以上是关于FlatList ref scrollToIndex 不是函数的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 ref 在 React Native Video 中编辑视频播放器道具
react-native FlatList 滚动到底部的聊天应用程序
如何使用有限的数组在React Native中使平面列表无限滚动