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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 09:21:01