react-three-fiber中如何访问map遍历传入的数据设置组件属性
问题根因
- Props取值层级错误:React函数组件的入参是所有传入属性的集合对象,你给组件传入
pinInfo={e}时,组件入参的实际结构为{ pinInfo: 对应e的点位数据 }。你直接将入参命名为pinInfo后访问pinInfo.pin_position,相当于在props根对象上找不存在的字段,自然返回undefined。 - demand渲染模式未触发重绘:Canvas设置
frameloop="demand"后,react-three-fiber不会自动逐帧更新画面,仅在手动调用invalidate()方法时才会重渲染,状态变更后没有主动触发重绘的话,新的位置数据不会同步到画布上。
修复代码
修正Pin组件实现
import { useLoader, useThree } from '@react-three/fiber' import { TextureLoader } from 'three' import { useEffect } from 'react' function Pin({ pinInfo }) { // 正确解构拿到传入的点位数据,可直接访问内部属性 const pinTexture = useLoader(TextureLoader, setPinColor(pinInfo.pin_color)); const { x_pos, y_pos } = pinInfo.pin_position; // 获取R3F提供的画布重绘方法 const { invalidate } = useThree(); // 点位数据变化时主动触发画布重绘 useEffect(() => { invalidate(); }, [pinInfo, invalidate]); return ( <mesh position={[x_pos, y_pos, 0]}> <planeGeometry args={[5, 5]} /> <meshBasicMaterial map={pinTexture} toneMapped={false} transparent={true} /> </mesh> ) }
补充列表渲染唯一key
遍历渲染组件时必须加唯一key,避免React虚拟DOM diff异常:
<Canvas linear flat frameloop="demand" orthographic camera={{ position: [0, 0, 50], zoom: 20, up: [0, 0, 1], far: 10000 }}> <Suspense fallback={null}> {moduleData.floor1.pins.map(e => // 替换成你数据里的唯一业务字段,不要用数组下标当key <Pin key={e.popup_title} pinInfo={e}/> )} <Scene mapImage={riverwalkMap}/> </Suspense> <MapControls enableRotate={false}/> </Canvas>
补充说明
- 如果后续有拖拽、实时动画这类高频更新需求,可以把Canvas的
frameloop改回默认值always,就不需要手动调用invalidate()触发重绘,根据业务场景选择即可。 - 只要你的点位state更新能触发Pin组件重渲染,上述逻辑就会自动同步位置到画布,不需要额外引入特殊hook。
内容的提问来源于stack exchange,提问作者sylargaf
相关产品推荐
相关产品推荐

