react-native-smooth-picker@1.1.3滚动时scrollToIndex报错及选中值异常问题排查与修复建议
解决 react-native-smooth-picker@1.1.3 的两个核心问题
我来帮你分析这两个问题的根源,并且给出具体的修复方案:
问题1:scrollToIndex is not a function 错误
这个错误有两个主要原因:
- 你没有在代码中声明
refPicker变量(直接用了ref={refPicker},但没定义const refPicker = React.useRef(null);),不过即使声明了,react-native-smooth-picker的组件ref并不暴露scrollToIndex方法——这个方法是React Native原生ScrollView的API,而该库没有把内部ScrollView的ref透传出来。 - 更关键的是:你完全不需要手动调用
scrollToIndex!因为你已经开启了magnet属性,这个属性会让组件自动将选中的项吸附到中间位置,手动调用反而会和库的内置逻辑冲突。
问题2:滚动时无法正确选中值并更新状态
这个问题的核心问题出在数据处理和状态更新逻辑的混乱:
data属性的map函数没有返回值:dataRows.map((o)=> { // let obj; return o.name })这行代码里,你把return注释掉了,导致每个item都是undefined,所以onSelected里的item是undefined,自然找不到对应的数据,setValue也就无法正确更新。- 重复的状态更新逻辑:你在
onSelected里调用handleChange,而handleChange又去设置selected状态,同时还尝试手动滚动,这会导致状态更新的竞态,让组件的选中状态和你的本地selected状态不同步。 ItemToRender组件没有返回任何JSX元素:你的代码里return ;是空的,这会导致选择器无法渲染任何选项,也是潜在的问题。
完整修复代码
下面是修复后的完整代码,我已经标注了关键的修改点:
import React from "react"; import { Text, View } from "react-native"; import SmoothPicker from "react-native-smooth-picker"; const opacities = { 0: 1, 1: 1, 2: 0.6, 3: 0.3, 4: 0.1 }; const sizeText = { 0: 20, 1: 15, 2: 10 }; // 修复:让组件返回正确的JSX元素 const ItemToRender = ({ item, index }, indexSelected, vertical) => { const selected = index === indexSelected; const gap = Math.abs(index - indexSelected); const opacity = gap > 3 ? opacities[4] : opacities[gap]; const fontSize = gap > 1 ? sizeText[2] : sizeText[gap]; return ( <View style={{ justifyContent: "center", alignItems: "center" }}> <Text style={{ opacity, fontSize, color: selected ? "#000" : "#999" }}> {item} </Text> </View> ); }; export default function SmoothPickerScreen({ navigation }) { const [selectedIndex, setSelectedIndex] = React.useState(1); const [value, setValue] = React.useState(null); const [dataRows, setDataRows] = React.useState([]); const data = [ { name: "A1", id: 1 }, { name: "A2", id: 2 }, { name: "A3", id: 3 }, { name: "A4", id: 4 }, { name: "A5", id: 5 }, { name: "A6", id: 6 }, { name: "A7", id: 7 }, { name: "A8", id: 8 }, { name: "A9", id: 9 }, { name: "A10", id: 10 }, ]; React.useEffect(() => { setDataRows(data); // 初始化时设置默认值 setValue(data[selectedIndex].id); }, []); // 合并状态更新逻辑,移除多余的handleChange const handleSelect = ({ item, index }) => { setSelectedIndex(index); const foundItem = dataRows.find((o) => o.name === item); if (foundItem) { setValue(foundItem.id); } }; return ( <View style={{ flex: 1, justifyContent: "center" }}> <SmoothPicker // 移除无用的ref,因为库不支持scrollToIndex keyExtractor={(_, index) => index.toString()} showsVerticalScrollIndicator={false} // 修复:正确返回item的name值 data={dataRows.map((o) => o.name)} scrollAnimation // 修复:直接使用合并后的handleSelect处理选中事件 onSelected={handleSelect} renderItem={(option) => ItemToRender(option, selectedIndex, true)} magnet /> {/* 可以添加一个文本显示当前选中的值,方便调试 */} <Text style={{ marginTop: 20, textAlign: "center" }}> 当前选中ID:{value} </Text> </View> ); }
关键修改说明
- 移除了
refPicker和手动滚动逻辑:依赖magnet属性自动完成选中项的定位。 - 修复了
data的map处理:确保每个item都是有效的名称字符串。 - 合并了状态更新逻辑:在
handleSelect中同时更新选中索引和对应的值,避免状态不同步。 - 修复了
ItemToRender的返回值:添加了Text组件来渲染选项内容,并应用了样式。 - 初始化时设置默认值:在useEffect中初始化
value为默认选中项的ID,让页面加载时就有正确的初始状态。
内容的提问来源于stack exchange,提问作者Jitendra Patwa
相关产品推荐
相关产品推荐

