FlatList ref scrollToIndex 不是函数
FlatList ref scrollToIndex is not a function
我正面临着 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()
效用函数,但它 returns null
.
我发现过去在 Stack Overflow 上多次发布过相同的问题,大多数都没有答案,或者对我不起作用。这些帖子也有点旧(一年左右),这就是为什么我再次发布相同的问题。
有没有人设法找到这个问题的solution/workaround?
编辑:可能的解决方法
当我在玩代码时,我尝试使用 ScrollView
组件而不是 FlatList
- scrollTo
方法有效!
更改仅针对 FlatList - ScrollView 特定道具(因此,对于 ScrolLView 它将是 childs 而不是 data={[...]}
和 renderItem={()=>{ ... }}
,等等),以及 componentDidMount 中的 scrollToIndex
方法被 scrollTo
.
取代
class 的渲染方法,带有 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>
请注意,ScrollView 没有 scrollToIndex()
方法,因此您必须手动跟踪子位置,也许,实现您自己的 scrollToIndex 方法。
我不会以此作为我问题的答案,因为潜在的问题仍然存在。但作为一种解决方法,也许你可以接受它并结束它......
与Animated.ScrollView:
- 为您的 FlatList 创建一个引用(旧方法只适用):
<ScrollView ref={ (ref) => (this.MyRef=ref) } />
- 使用
this.myRef.getNode().scrollToIndex
访问 scrollToIndex
不幸的是,Animated.FlatList
目前无法正常工作...
使用 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(); }
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,
},
});
如果我完全错了,请告诉我...
因为ScrollView没有scrollToOffset
功能,只有scrollTo
功能
所以让函数 scrollTo
与 ScrollView 或 scrollToOffset
与 FlatList 一起使用,它工作正常。
TL;DR;
this.myRef = React.createRef();
this.myRef.current.doSomething(); // note the use of 'current'
长版:
虽然我尝试的想法是正确的,但我原来 post 中的错误似乎很愚蠢。在我看来,文档并不清楚(可能......)。无论如何...
React.createRef
returns 一个带有几个字段的对象,所有这些对开发人员来说都是无用的(在后面被 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 的字段上将未定义的值作为函数调用,您的代码将会崩溃。如果您错误地在多个组件上重复使用相同的引用,或者如果您附加它的组件没有该方法(即 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 的其他人有用。干杯:)
如果您使用的是 'KeyboardAwareFlatList',则效果很好:
https://github.com/APSL/react-native-keyboard-aware-scroll-view/issues/372
简而言之,使用 useRef 并使用 KeyboardAwareFlatList
的 innerRef
属性 而不是 ref
属性.
我正面临着 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()
效用函数,但它 returns null
.
我发现过去在 Stack Overflow 上多次发布过相同的问题,大多数都没有答案,或者对我不起作用。这些帖子也有点旧(一年左右),这就是为什么我再次发布相同的问题。
有没有人设法找到这个问题的solution/workaround?
编辑:可能的解决方法
当我在玩代码时,我尝试使用 ScrollView
组件而不是 FlatList
- scrollTo
方法有效!
更改仅针对 FlatList - ScrollView 特定道具(因此,对于 ScrolLView 它将是 childs 而不是 data={[...]}
和 renderItem={()=>{ ... }}
,等等),以及 componentDidMount 中的 scrollToIndex
方法被 scrollTo
.
取代
class 的渲染方法,带有 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>
请注意,ScrollView 没有 scrollToIndex()
方法,因此您必须手动跟踪子位置,也许,实现您自己的 scrollToIndex 方法。
我不会以此作为我问题的答案,因为潜在的问题仍然存在。但作为一种解决方法,也许你可以接受它并结束它......
与Animated.ScrollView:
- 为您的 FlatList 创建一个引用(旧方法只适用):
<ScrollView ref={ (ref) => (this.MyRef=ref) } />
- 使用
this.myRef.getNode().scrollToIndex
访问
scrollToIndex
Animated.FlatList
目前无法正常工作...
使用 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(); }
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,
},
});
如果我完全错了,请告诉我...
因为ScrollView没有scrollToOffset
功能,只有scrollTo
功能
所以让函数 scrollTo
与 ScrollView 或 scrollToOffset
与 FlatList 一起使用,它工作正常。
TL;DR;
this.myRef = React.createRef();
this.myRef.current.doSomething(); // note the use of 'current'
长版:
虽然我尝试的想法是正确的,但我原来 post 中的错误似乎很愚蠢。在我看来,文档并不清楚(可能......)。无论如何...
React.createRef
returns 一个带有几个字段的对象,所有这些对开发人员来说都是无用的(在后面被 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 的字段上将未定义的值作为函数调用,您的代码将会崩溃。如果您错误地在多个组件上重复使用相同的引用,或者如果您附加它的组件没有该方法(即 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 的其他人有用。干杯:)
如果您使用的是 'KeyboardAwareFlatList',则效果很好: https://github.com/APSL/react-native-keyboard-aware-scroll-view/issues/372
简而言之,使用 useRef 并使用 KeyboardAwareFlatList
的 innerRef
属性 而不是 ref
属性.