如何让我的页面等待钩子获取所有数据?

How make my page wait till the hook got all data?

我正在构建一个基于 TypeScript 模板的 React 应用程序,我的一个页面在挂钩完成加载之前正在加载。

我试过 makings async await 但它是一个钩子,效果不佳。

我如何构建一些东西来等待我的挂钩完成,然后将其加载到页面上?

我的页面:

export function Home(){


    const { topEventsSelected } = useGetTopEvents(3);

    

    return(
        <div className="d-flex flex-column min-vh-100">
            <NavBar/>
                
                <div className="container">
                    <div className="row mt-4 mb-4 gap">
                        <div className="col-md">
                            <div className="card">
                                <div className="sizingt d-flex card-body flex-column align-items-center sizingt">
                                    <h1>TOP Eventos</h1>
                                    {topEventsSelected.map((eventoInfo)=>
                                        moment(eventoInfo.dataFinal).isBefore() || eventoInfo.cancelado === 'Y' ? 
                                            (
                                                console.log()
                                            ):(
                                                <BlueCard props={eventoInfo}/>
                                            )
                                        
                                    )}
                                </div>
                            </div>
                        </div>
                        

这是我的钩子(注意文件是.ts):

export function useGetTopEvents(quant: number){
    const [eventValues, setEventValues] = useState<Evento[]>([]);
    const [topEvents, setTopEvents] = useState<Evento[]>([]);
    const [topEventsSelected, setTopEventsSelected] = useState<Evento[]>([]);
    
    function organizeEvents(){
        //organazing events by confirmed users
        let topAllEvents = []
        for(let organizer of eventValues){
            if(organizer.confirmNumb > 0){
                topAllEvents.push(organizer)
            }
        }
        topAllEvents.sort((a,b) => b.confirmNumb - a.confirmNumb)
        setTopEvents(topAllEvents)

        //organazing events by quantity selected
        let topSelected = topAllEvents;
        topSelected.sort((a,b) => b.confirmNumb - a.confirmNumb).slice(0,3);
        setTopEventsSelected(topSelected);
    }

    useEffect(() =>{
        const eventRef = database.ref(`eventos`);

        eventRef.once('value', evento => {
            //console.log(evento.val())
            const databaseEventos = evento.val();

            const firebaseEvent: FirebaseEventos = databaseEventos ?? {};
            
            const parsedEventos = Object.entries(firebaseEvent).map(([key, value])=>{
                return{
                    id: key,
                    autorID: value.authorID,
                    autorNome: value.authorName,
                    categoria: value.category,
                    dataInicio: value.startDate,
                    dataFinal: value.endDate,
                    titulo: value.title,
                    cancelado: value.canceled,
                    confirmNumb: Object.entries(value.confirmados ?? {}).length
                }
            }) 
            
            //console.log(parsedEventos)
            
            setEventValues(parsedEventos);

            organizeEvents();
        })

    }, [quant])

    return{topEvents, topEventsSelected}
}

我认为解决方案是在渲染组件上添加条件渲染。在您的自定义挂钩中,您可以再添加一个加载状态,然后您可以基于该状态渲染您的组件。

export function useGetTopEvents(quant: number) {

  const [loading,set] = useState<Boolean>(true)

  function organizeEvents() {
    //organazing events by confirmed users
    ...your function
  }

  useEffect(() => {
      ...
      //console.log(parsedEventos)

      setEventValues(parsedEventos);
      setLoading(false) // set the state to false
      organizeEvents();
    });
  }, [quant]);

  return {topEvents, topEventsSelected, loading};

  // also return the loading state so you could use it with your custom hook
}

那么你可以使用如下加载

const { topEventsSelected ,loading} = useGetTopEvents(3);


      return(
        <div className="d-flex flex-column min-vh-100">
            <NavBar/>
                
               {loading ? ...loading : your render login}
)

最好的方法是有条件地呈现 return 中的元素。

const [data, setData] = useState(null);

在您的 return 方法中

   return ({
data : <>Your component</> ? <LoadingState />
})

故障排除 我意识到代码将数据分配给方法 setEventValues(parsedEventos); 上的参数所花费的时间更长,因此,由于它是 multi-thread,它开始 运行 organizeEvents() 在完成之前将数据分配给 setEventValues。

通过函数参数发送数据来解决这个问题:organizeEvents(parsedEventos)然后处理信息并将其保存在常量中。

我还将 organizeEvents 更改为异步,从而避免损坏

这里是钩子的最终代码:

export function useGetTopEvents(quant: number){
    
    const [topEvents, setTopEvents] = useState<Evento[]>([]);
    const [topEventsSelected, setTopEventsSelected] = useState<Evento[]>([]);

    const [loading, setLoading] = useState(true)
    
    async function organizeEvents(eventValues: Evento[]){
        //organazing events by confirmed users

        let topAllEvents:Evento[] = <Evento[]>[];

        await eventValues.forEach(element =>{
            if(element.confirmNumb > 0){
                topAllEvents.push(element)
            }
        })

        await topAllEvents.sort((a,b) => b.confirmNumb - a.confirmNumb)
        await setTopEvents(topAllEvents)

        //organazing events by quantity selected
        let topSelected = topAllEvents;
        await topSelected.sort((a,b) => b.confirmNumb - a.confirmNumb).slice(0,3);
        await setTopEventsSelected(topSelected);
        
        await setLoading(false)
        
    }

    useEffect(() =>{
        const eventRef = database.ref(`eventos`);

        eventRef.once('value', evento => {
            //console.log(evento.val())
            const databaseEventos = evento.val();

            const firebaseEvent: FirebaseEventos = databaseEventos ?? {};
            
            const parsedEventos = Object.entries(firebaseEvent).map(([key, value])=>{
                return{
                    id: key,
                    autorID: value.authorID,
                    autorNome: value.authorName,
                    categoria: value.category,
                    dataInicio: value.startDate,
                    dataFinal: value.endDate,
                    titulo: value.title,
                    cancelado: value.canceled,
                    confirmNumb: Object.entries(value.confirmados ?? {}).length
                }
            }) 
            
            //console.log(parsedEventos)
            
            organizeEvents(parsedEventos);
            
        })

    }, [quant])

    return{topEvents, topEventsSelected, loading}
}