You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native自定义Select组件报错:View config getter callback异常求助

React Native自定义Select组件报错解决方案

我在React Native中使用自定义Select组件时遇到以下错误,该组件在Web版本可正常运行,但在React Native中失效:

Invariant Violation: View config getter callback for component path must be a function (received undefined). Make sure to start component names with a capital letter.

组件代码如下:

import { TouchableOpacity } from "react-native";
import React, { useEffect, useState } from "react";
import { StyleSheet, Text, View } from "react-native";
import { RiArrowDropDownLine, RiArrowDropUpLine, RiCloseLine } from "react-icons/ri"

const Select = React.forwardRef((props, ref) => {
    const {
        data,
        boxStyles,
        placeholder,
        setSelected,
    } = props;
    const [current, setCurrent] = useState(null);
    const [isClosed, setisClosed] = useState(true);

    useEffect(() => {
        setSelected(current)
    }, [current])

    const handleReset = () => {
        setCurrent(null)
        setSelected(null)
    }
    const handleOpen = () => setisClosed(flag => !flag);
    const handleSelect = (name) => {
        setCurrent(name)
        handleOpen()
    };

    const options = data?.map((item, index) => {
        return <TouchableOpacity
            style={styles.option}
            onPress={() => handleSelect(item.value)}
            key={index}>
            <Text>{item.label}</Text>
        </TouchableOpacity>
    });

    return <View style={boxStyles} >
        <TouchableOpacity style={styles.wrapper} onPress={handleOpen}>
            <Text>{current || placeholder}</Text>
            {current ?
                <TouchableOpacity onPress={() => handleReset()} ref={ref}>
                    <RiCloseLine />
                </TouchableOpacity>
            :
                isClosed ? <RiArrowDropDownLine/> : <RiArrowDropUpLine />
            }
        </TouchableOpacity>
        <View style={[styles.dropdown, isClosed && styles.isClosed]} >{options}</View>
    </View>
})

const styles = StyleSheet.create({
    isClosed: {height: 0, display: "none"},
    wrapper:{ borderWidth:1,borderRadius:10,borderColor:'gray',paddingHorizontal:20,paddingVertical:12,flexDirection:'row',justifyContent:'space-between',fontSize: 22},
    dropdown:{ borderWidth:1,borderRadius:10,borderColor:'gray',marginTop:10,overflow:'hidden'},
    option:{ paddingHorizontal:20,paddingVertical:8,overflow:'hidden'},
    disabledoption:{ paddingHorizontal:20,paddingVertical:8,flexDirection:'row',alignItems:'center', backgroundColor:'whitesmoke',opacity:0.9}
})

export default Select

错误原因

这个报错的核心问题是**react-icons库为Web环境设计,依赖DOM元素,无法直接在React Native中使用**。React Native的组件系统不识别react-icons导出的组件,因此抛出组件配置未找到的错误。另外代码中还有React Native不支持的样式属性display: "none",也会导致渲染异常。

解决步骤

1. 替换图标库

使用React Native专用的图标库,比如@react-native-vector-icons(普通React Native项目)或@expo/vector-icons(Expo项目)。

安装依赖

  • 普通React Native项目:
    npm install @react-native-vector-icons/react-native-vector-icons
    
  • Expo项目:
    npx expo install @expo/vector-icons
    

替换图标组件

将原代码中的react-icons导入替换为对应Native图标库的组件,示例如下:

// 普通项目示例,使用MaterialCommunityIcons
import Icon from '@react-native-vector-icons/MaterialCommunityIcons';
// Expo项目示例,使用Ionicons
// import { Ionicons } from '@expo/vector-icons';

然后在组件中替换图标:

  • 关闭图标:<Icon name="close" size={24} color="gray" />
  • 下拉箭头:<Icon name="chevron-down" size={24} color="gray" />
  • 上拉箭头:<Icon name="chevron-up" size={24} color="gray" />

2. 修正不兼容的样式

React Native不支持display: "none",改用height: 0 + overflow: 'hidden' + opacity: 0来隐藏元素:

isClosed: { height: 0, overflow: 'hidden', opacity: 0 },

另外原代码中wrapper样式里的fontSize应该放到Text组件的样式中,否则不会生效,需要单独提取:

// 在styles中添加
wrapperText: { fontSize: 22 },
// 在组件中应用
<Text style={styles.wrapperText}>{current || placeholder}</Text>

修改后的完整代码

import { TouchableOpacity } from "react-native";
import React, { useEffect, useState } from "react";
import { StyleSheet, Text, View } from "react-native";
import Icon from '@react-native-vector-icons/MaterialCommunityIcons';

const Select = React.forwardRef((props, ref) => {
    const {
        data,
        boxStyles,
        placeholder,
        setSelected,
    } = props;
    const [current, setCurrent] = useState(null);
    const [isClosed, setisClosed] = useState(true);

    useEffect(() => {
        setSelected(current)
    }, [current])

    const handleReset = () => {
        setCurrent(null)
        setSelected(null)
    }
    const handleOpen = () => setisClosed(flag => !flag);
    const handleSelect = (name) => {
        setCurrent(name)
        handleOpen()
    };

    const options = data?.map((item, index) => {
        return <TouchableOpacity
            style={styles.option}
            onPress={() => handleSelect(item.value)}
            key={index}>
            <Text>{item.label}</Text>
        </TouchableOpacity>
    });

    return <View style={boxStyles} >
        <TouchableOpacity style={styles.wrapper} onPress={handleOpen}>
            <Text style={styles.wrapperText}>{current || placeholder}</Text>
            {current ?
                <TouchableOpacity onPress={() => handleReset()} ref={ref}>
                    <Icon name="close" size={24} color="gray" />
                </TouchableOpacity>
            :
                isClosed ? <Icon name="chevron-down" size={24} color="gray" /> : <Icon name="chevron-up" size={24} color="gray" />
            }
        </TouchableOpacity>
        <View style={[styles.dropdown, isClosed && styles.isClosed]} >{options}</View>
    </View>
})

const styles = StyleSheet.create({
    isClosed: { height: 0, overflow: 'hidden', opacity: 0 },
    wrapper:{ 
        borderWidth:1,
        borderRadius:10,
        borderColor:'gray',
        paddingHorizontal:20,
        paddingVertical:12,
        flexDirection:'row',
        justifyContent:'space-between',
        alignItems: 'center'
    },
    wrapperText: { fontSize: 22 },
    dropdown:{ 
        borderWidth:1,
        borderRadius:10,
        borderColor:'gray',
        marginTop:10,
        overflow:'hidden'
    },
    option:{ 
        paddingHorizontal:20,
        paddingVertical:8,
        overflow:'hidden'
    },
    disabledoption:{ 
        paddingHorizontal:20,
        paddingVertical:8,
        flexDirection:'row',
        alignItems:'center', 
        backgroundColor:'whitesmoke',
        opacity:0.9
    }
})

export default Select

内容的提问来源于stack exchange,提问作者chackerian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 10:30:10