ค้นหาเว็บไซต์

javascript - การเรียกฟังก์ชัน async ที่กำลังดึงข้อมูลเริ่มต้นในตัวสร้างของคลาส JS ทำได้หรือไม่?


ฉันกำลังสร้างตัวอย่างแอปด้วย Mobx และ Mobx React Lite เพื่อเรียนรู้วิธีการใช้ไลบรารีการจัดการสถานะนี้ แอปต้องโหลดคำถามเมื่อผู้ใช้เข้าชมหน้านี้ สามารถเรียกโหลดข้อมูลเริ่มต้นในคอนสตรัคเตอร์แบบนี้ได้ไหม? มันอาจทำให้เกิดบั๊กได้หรือไม่?

ความกังวลของฉันคือมันอาจจะเกิดขึ้นอีกครั้ง แต่ฉันไม่แน่ใจว่านั่นอาจเป็นความกังวลเดียวที่ฉันควรมีหรือไม่

คุณจะแนะนำรูปแบบอื่นอะไรถ้านี่เสี่ยง?

ไอเดียทางเลือกของฉันคือการเอามันออกจากบริบทเมื่อพวกเขาคลิกปุ่ม "เริ่มทำแบบทดสอบ" และมีหน้าจอโหลดขณะดึงข้อมูลมา วิธีนี้น่าจะเป็นวิธีที่ควรเกิดขึ้นที่สุด แต่ฉันก็แค่สงสัยว่าที่ฉันทำไปนั้นก็โอเคหรือไม่เช่นกัน

import { observable, action } from "mobx";
import { getQuestions } from "../api/api";

export interface Question {
    category: string;
    type: string;
    question: string;
    correct_answer: string;
    incorrect_answers: string[];
}

export class TriviaStore {

    constructor() {
        // Is this bad?
        (async() => {
            await this.loadQuestions();
        })()
    }

    @observable questions: Question[] = [];
    @observable currentQuestion: number = 0;

    @action
    async loadQuestions() {
        let questions: Question[] = await getQuestions();
        this.questions = questions;
    }
    @action
    nextQuestion() {
        this.currentQuestion++;
    }
}

ร้านค้าจะถูกสร้างขึ้นเพียงครั้งเดียวในผู้ให้บริบทดังนี้:

import React from 'react';
import { TriviaStore } from '../stores/TriviaStore';

/**
 * Store Types.
 * Add any new stores here so the context type is updated.
 */
type RootStateContextValue = {
    triviaStore: TriviaStore;
}

const RootStateContext = React.createContext<RootStateContextValue>({} as RootStateContextValue);

/**
 * Stores
 * Use this area to create instances of stores to pass down.
 */
const triviaStore = new TriviaStore();

/**
 * Root State Provider
 * @returns global state context wrapper.
 */
export const RootStateProvider: React.FC<React.PropsWithChildren<{}>> = ({children}) => {
    // Finally pass new stores into the object below to send them to global state.
    return (
        <RootStateContext.Provider
            value={{
                triviaStore,
            }}
        >
            {children}
        </RootStateContext.Provider>
    );
}

export const useGlobalState = () => React.useContext(RootStateContext);

คำตอบ #1

การเริ่มต้นร้านค้าก่อนที่ข้อมูลทั้งหมดจะถูกโหลดเป็นเรื่องที่ดีในความคิดเห็นของฉัน คุณสามารถเพิ่มสถานะการโหลดโดยตรงไปที่ร้านค้า การวางฟังก์ชันแบบอะซิงค์เป็นเมธอดในร้านค้าเป็นความคิดที่ดี แม้ว่าฉันคิดว่าฟังก์ชันอะซิงค์ที่ถูกเรียกใช้งานทันทีไม่มีผลและร้านค้าจะถูกเริ่มต้นก่อนที่คำถามจะถูกโหลด ดูตัวอย่างนี้:

@observable loading = true

constructor() {
  // Same as with your wrapper, constructor cannot be made async.
  this.loadQuestions()
}

@action
async loadQuestions() {
  let questions: Question[] = await getQuestions()
  // Newer versions of MobX will warn if runInAction missing after async call.
  runInAction(() => {
    this.questions = questions
    this.lading = false
  })
}

ในความคิดเห็นของฉัน ส่วนที่ไม่ค่อยดีคือการผสม MobX store กับ React Context ซึ่งฉันคิดว่าไม่จำเป็นเพราะคุณสามารถนำเข้า store โดยตรงจากที่ไหนก็ได้อยู่แล้ว

คำตอบ #2

แม้ว่า React จะอนุญาตให้คุณดึงข้อมูลบางอย่างและจะไม่ทำให้เกิดข้อบกพร่องใด ๆ ใน constructor แต่ก็ไม่แนะนำโดยนักพัฒนาของ React และไม่ใช่แนวทางที่ดี คุณควรดึงข้อมูลของคุณใน componentDidMount() แทน

ถ้าการออกแบบของคุณต้องการการดึงข้อมูลหลายครั้งหลังจากที่คุณโหลดหน้าเว็บ คุณสามารถลองทำใน componentDidUpdate() และอัปเดตสภาวะเริ่มต้นของคุณ