Reactjs 使用react suspense从Firebase异步加载

Reactjs 使用react suspense从Firebase异步加载,reactjs,concurrency,firebase-storage,react-suspense,Reactjs,Concurrency,Firebase Storage,React Suspense,我试图使用悬念从Firebase存储加载GLTF模型。为此,我需要首先使用getDownloadURL方法异步获取模型的URL,然后才能加载它。我所看到的是加载程序不断地被调用,但响应从未被使用过——我确信我错过了一些简单的东西 我将代码放在这里,它使用的示例在internet上似乎相当常见,我替换了firebase访问器(因为它需要专用访问密钥才能正常工作),但是替换函数在超时后返回url非常简单 总结一下沙盒,如果它是一个将下载url包装在挂起函数中的函数,请注意: function get

我试图使用悬念从Firebase存储加载GLTF模型。为此,我需要首先使用getDownloadURL方法异步获取模型的URL,然后才能加载它。我所看到的是加载程序不断地被调用,但响应从未被使用过——我确信我错过了一些简单的东西

我将代码放在这里,它使用的示例在internet上似乎相当常见,我替换了firebase访问器(因为它需要专用访问密钥才能正常工作),但是替换函数在超时后返回url非常简单

总结一下沙盒,如果它是一个将下载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>
    );
}
导出默认功能模型(道具){
constmodeldata=getModelData(props.path);
const gltf=useGLTF(modelData.url.read());
返回(
);
}

suspend函数正确地抛出其承诺,承诺解析设置结果,但suspend函数本身被连续调用,并且结果方法始终未定义。

getDownloadURL是异步的,因此您需要这样编写函数:

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>
    );
}
异步函数getModelData(路径){ const storage=firebase.storage(); const urlPromise=wait storage.ref(path).getDownloadURL(); 返回{url:suspend(urlclomise)}; }
好的,所以我继续调查,并得出结论,这是行不通的-我的问题是,我不断地重新创建包装,而不是创建一次,让承诺完成并更改吊杆状态。我尝试切换到在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}/>
}
函数模型fromURL(道具){
constgltf=useGLTF(props.url);
返回(
);
}
导出默认功能模型(道具){
const[url,setUrl]=useState();
useffect(()=>{
firebase.storage();
},[props.path]);
如果(!url){
返回null;
}
返回
}

让suspend机制正常工作会很好,但似乎这种模式必须满足要求。

感谢您花时间回答-我认为这种模式的要点是将getModelData返回的承诺传递给suspend包装器,以便使用其带有suspended promise的then方法等待它被扔回堆栈。我不相信让它异步并等待它在这里有帮助。是的,但你不能把它作为承诺返回。这就是问题所在。你返回一个在允诺中包含somwhere的对象。