React Three Fiber中如何访问数组内组件的状态与属性?
React Three Fiber 组件内部状态与属性访问问题
我正在使用React Three Fiber,有两个组件:Plat(创建立方体)和Boxes(生成立方体数组)。
Plat 组件代码
export function Plat() { const [active, setActive] = useState(0) const { scale } = useSpring({ scale: active ? 1 : 0.4 }) const [mat] = useState(() => new THREE.TextureLoader().load('/matcap.png')) function Shape(props) { return ( <animated.mesh {...props} scale={scale} onPointerOver={() => setActive(Number(!active))} > <RoundedBox args={[60,20,60]} radius={4} smoothness={4} position={[0, -10, 0]} dispose={null} > <meshMatcapMaterial matcap={mat} /> </RoundedBox> </animated.mesh> ); } useEffect(() => { (function() { setActive(1) })(); },[]); return ( <Shape /> ) }
Boxes 组件代码
import {Plat} from './Plat' export default function Boxes() { function MyShape(props) { return ( <mesh {...props} > <Plat /> </mesh> ); } const [shapes, setShapes] = useState([ <MyShape key={0} position={[100, 100, 100]} />, <MyShape key={1} position={[120, 120, 120]} />, <MyShape key={2} position={[130, 130, 130]} /> ]); return ( <group > {[...shapes]} </group> ) }
我希望能访问数组中每个Plat组件内部的变量,比如实现console.log(shapes[2].position)查看指定组件位置、修改该组件位置,或是调用shapes[1].setActive(1)改变组件active状态,想知道这类操作是否可行及实现方法。
实现方案
你当前写法里的shapes数组存的是React元素,不是组件实例,所以直接访问属性或调用内部方法行不通,以下是两种可行的实现思路:
1. 状态提升:统一管理状态与属性
把Plat的active状态和立方体的position都提到Boxes组件中集中管理,这样就能直接操作这些数据:
修改 Plat 组件
让Plat接收外部传入的状态和回调,不再内部维护状态:
export function Plat({ active, onToggleActive }) { const { scale } = useSpring({ scale: active ? 1 : 0.4 }) const [mat] = useState(() => new THREE.TextureLoader().load('/matcap.png')) function Shape(props) { return ( <animated.mesh {...props} scale={scale} onPointerOver={onToggleActive} > <RoundedBox args={[60,20,60]} radius={4} smoothness={4} position={[0, -10, 0]} dispose={null} > <meshMatcapMaterial matcap={mat} /> </RoundedBox> </animated.mesh> ); } return ( <Shape /> ) }
修改 Boxes 组件
用对象数组存储每个立方体的完整状态,替代直接存储React元素:
import { Plat } from './Plat' import { useState } from 'react' export default function Boxes() { // 存储每个立方体的key、位置、激活状态 const [cubeStates, setCubeStates] = useState([ { key: 0, position: [100, 100, 100], active: 1 }, { key: 1, position: [120, 120, 120], active: 1 }, { key: 2, position: [130, 130, 130], active: 1 } ]) // 切换指定索引立方体的激活状态 const toggleActive = (index) => { setCubeStates(prev => { const newStates = [...prev] newStates[index].active = Number(!newStates[index].active) return newStates }) } // 修改指定索引立方体的位置并打印 const updatePosition = (index, newPosition) => { setCubeStates(prev => { const newStates = [...prev] newStates[index].position = newPosition return newStates }) console.log(newPosition) } return ( <group> {cubeStates.map((state, index) => ( <mesh key={state.key} position={state.position}> <Plat active={state.active} onToggleActive={() => toggleActive(index)} /> </mesh> ))} </group> ) }
此时你可以直接操作cubeStates数组实现需求:
- 查看位置:
console.log(cubeStates[2].position) - 修改位置:
updatePosition(2, [150, 150, 150]) - 激活指定立方体:
toggleActive(1)
2. 使用 Refs 获取组件实例(保留内部状态场景)
如果需要保留Plat内部的状态管理,可以通过forwardRef和useImperativeHandle让父组件获取组件实例并调用内部方法:
修改 Plat 组件
import { forwardRef, useImperativeHandle, useState, useEffect } from 'react' import { useSpring } from '@react-spring/three' export const Plat = forwardRef((props, ref) => { const [active, setActive] = useState(0) const { scale } = useSpring({ scale: active ? 1 : 0.4 }) const [mat] = useState(() => new THREE.TextureLoader().load('/matcap.png')) // 暴露给父组件的方法 useImperativeHandle(ref, () => ({ setActive: (val) => setActive(val), getActive: () => active })) function Shape(props) { return ( <animated.mesh {...props} scale={scale} onPointerOver={() => setActive(Number(!active))} > <RoundedBox args={[60,20,60]} radius={4} smoothness={4} position={[0, -10, 0]} dispose={null} > <meshMatcapMaterial matcap={mat} /> </RoundedBox> </animated.mesh> ); } useEffect(() => { setActive(1) },[]); return ( <Shape /> ) })
修改 Boxes 组件
创建refs数组存储Plat实例,同时单独管理位置状态:
import { Plat } from './Plat' import { useState, useRef } from 'react' export default function Boxes() { const cubeRefs = useRef([]) // 管理所有立方体的位置 const [positions, setPositions] = useState([ [100, 100, 100], [120, 120, 120], [130, 130, 130] ]) // 调用第二个Plat的setActive方法并打印激活状态 const activateSecondCube = () => { cubeRefs.current[1]?.setActive(1) console.log('第二个立方体激活状态:', cubeRefs.current[1]?.getActive()) } // 修改第三个立方体的位置并打印 const updateThirdCubePosition = () => { const newPos = [160, 160, 160] setPositions(prev => { const newPositions = [...prev] newPositions[2] = newPos return newPositions }) console.log('第三个立方体新位置:', newPos) } return ( <group> {positions.map((pos, index) => ( <mesh key={index} position={pos}> <Plat ref={el => cubeRefs.current[index] = el} /> </mesh> ))} </group> ) }
这种方式下,你可以通过cubeRefs.current[index]访问对应Plat组件暴露的方法,通过positions数组管理和修改位置。
内容的提问来源于stack exchange,提问作者jenepix
相关产品推荐
相关产品推荐

