0

我正在尝试使用 suspense 从 Firebase 存储加载 GLTF 模型。为此,我需要先使用 getDownloadURL 方法异步获取模型的 URL,然后才能加载它。我所看到的是加载程序被反复调用,但从未使用过响应 - 我确定我错过了一些简单的东西..

我已将代码放入此代码沙箱中,它使用了在互联网上似乎相当常见的示例,我已替换了 firebase 访问器(因为它需要私有访问密钥才能按预期工作)但替换函数返回一个相当简单的超时后的网址。

总结一下沙盒,如果它是一个获取下载 url 的函数,它包裹在一个挂起函数中:

function getModelData(path) {
    const storage = firebase.storage();
    const urlPromise = storage.ref(path).getDownloadURL();

    return { url: suspend(urlPromise) };
}

这在我的代码中使用如下:

export default function Model(props) {
    const modelData = getModelData(props.path);
    const gltf = useGLTF(modelData.url.read());

    return (
        <mesh rotation={props.rotation} position={props.position} scale={props.scale}>
            <primitive object={gltf.scene.clone(true)} dispose={null}/>
        </mesh>
    );
}

挂起函数正确地抛出了它的promise,并且promise 解析了设置结果,但是挂起函数本身不断被调用并且result 方法总是未定义。

4

2 回答 2

0

好的,所以我继续调查并得出结论,这是行不通的 - 我遇到的问题是我不断地重新创建包装器而不是创建一次并让承诺完成并更改吊带状态。我尝试切换到在 useEffect 钩子中设置状态,并且仅在设置状态时才加载 gltf,但这会导致渲染上的钩子数量不一致的错误。

相反,我使用状态来设置模型 URL 并将渲染模型放入第二类:

function ModelFromUrl(props) {
    const gltf = useGLTF(props.url);

    return (
        <mesh rotation={props.rotation || [0, 0, 0]} position={props.position || [0, 0, 0]} scale={props.scale || [1, 1, 1]}>
            <primitive object={gltf.scene.clone(true)} dispose={null}/>
        </mesh>
    );
}
export default function Model(props) {
    const [url, setUrl] = useState();

    useEffect(() => {
        firebase.storage().ref(props.path).getDownloadURL().then(url => setUrl(url));
    }, [props.path]);
    if (! url) {
        return null;
    }
    return <ModelFromUrl {...props} url={url}/>
}

让悬念机制工作会很好,但似乎这种模式就足够了。

于 2021-05-30T06:57:41.313 回答
0

The getDownloadURL is asyncrhonous so you would need to write your functions like this:

async function getModelData(path){
    const storage = firebase.storage();
    const urlPromise = await storage.ref(path).getDownloadURL();

    return { url: suspend(urlPromise) };
}

于 2021-05-29T11:24:27.170 回答