Expo React Native使用Json.map()实现动态数据点击切换显隐
React Native 动态列表项独立显隐解决方案
你遇到的问题根源是所有动态渲染的列表项共用了同一个全局布尔状态showSlide,修改状态时所有项的显隐逻辑会同步触发,才会出现点击一个元素所有项都跟着切换显隐的问题。可以通过以下两种方案解决:
方案1:拆分子组件(更推荐)
将单个客户项封装为独立组件,每个组件内部维护自己的显隐状态,完全互不干扰,同时实现了逻辑解耦。
// 单独封装的客户项组件 const CustomerItem = ({ customer }) => { // 每个项独立维护显隐状态 const [showSlide, setShowSlide] = useState(false); return ( <TouchableOpacity onPress={() => setShowSlide(!showSlide)}> <Text style={styles.paragraph}> {customer.name} </Text> {showSlide ? ( <View> <Text>{customer.requests[0].title}</Text> </View> ) : null} </TouchableOpacity> ) } // 改造后的App组件 export default function App() { const [showSlide, setShowSlide] = useState(false); return ( <View style={styles.container}> {/* 原有静态示例保持不变 */} <TouchableOpacity onPress={() => {setShowSlide(!showSlide)}}> <Text style={styles.paragraph}> {dataC.customer[0].name} </Text> {showSlide ? ( <View> <Text>{dataC.customer[0].requests[0].title}</Text> </View> ) : null} </TouchableOpacity> <View style={{width:"100%", height:5, backgroundColor:"red", marginTop: 10, marginBottom: 10}}></View> <Text style={{textAlign: "center"}}>动态示例</Text> {/* 动态渲染直接调用封装好的子组件 */} { dataC.customer.map((customer, index) => ( // key优先使用数据自带的唯一ID,无唯一ID时临时用index <CustomerItem key={customer.id || index} customer={customer} /> ))} </View> ); }
方案2:父组件存储激活项标识
如果不想拆分子组件,可在父组件用状态存储当前展开项的唯一标识,通过匹配标识控制对应项的显隐。
export default function App() { const [showSlide, setShowSlide] = useState(false); // 存储当前展开的客户ID,初始为null代表无展开项 const [activeCustomerId, setActiveCustomerId] = useState(null); const toggleSlide = (customerId) => { // 点击已展开项则收起,否则切换为当前点击项的ID setActiveCustomerId(activeCustomerId === customerId ? null : customerId) } return ( <View style={styles.container}> {/* 原有静态示例保持不变 */} <TouchableOpacity onPress={() => {setShowSlide(!showSlide)}}> <Text style={styles.paragraph}> {dataC.customer[0].name} </Text> {showSlide ? ( <View> <Text>{dataC.customer[0].requests[0].title}</Text> </View> ) : null} </TouchableOpacity> <View style={{width:"100%", height:5, backgroundColor:"red", marginTop: 10, marginBottom: 10}}></View> <Text style={{textAlign: "center"}}>动态示例</Text> { dataC.customer.map((customer, index) => { // 优先取数据自带的唯一ID,无则用index代替 const customerId = customer.id || index return ( <TouchableOpacity key={customerId} onPress={() => toggleSlide(customerId)}> <Text style={styles.paragraph}> {customer.name} </Text> {/* 仅当前项ID匹配激活ID时展示内容 */} {activeCustomerId === customerId ? ( <View> <Text>{customer.requests[0].title} </Text> </View> ) : null} </TouchableOpacity> ) })} </View> ); }
补充说明
- 若业务允许多个项同时展开,直接使用方案1即可满足需求;方案2可将state改为存储ID数组,判断当前ID是否在数组中控制显隐即可。
- 循环项的
key属性优先使用数据自带的唯一字段(如客户ID),避免列表顺序变化时出现渲染异常。
内容的提问来源于stack exchange,提问作者B.T
相关产品推荐
相关产品推荐

