我如何减慢我的快速服务器响应以允许 react-admin getOne() 函数工作?

How do I slow down my express server response to allow the react-admin getOne() function to work?

我已经创建了 VetCreate 和 VetEdit 函数来创建新记录,然后分别编辑该记录(代码如下)。我遇到的问题是返回了成功的创建响应,但新创建的 ID 未填充到获取记录的请求中。

我在我认为需要的地方设置了 async/await 关键字,但记录到控制台的详细信息清楚地表明某些地方没有正常工作。如果我在返回列表屏幕后尝试编辑记录,API 会按预期工作,returns 详细信息。

我已经添加了我能想到的所有代码和屏幕截图,但如果需要更多内容,请询问。

VetCreate
export const VetCreate = (props) => (
  <Create title="Credit Application" aside={<CreateAside />} {...props}>
    <TabbedForm toolbar={<VetCreateToolbar />} redirect="show">
      <FormTab label="applicant">
        <DateInput disabled label="Date Created" source="DateCreated" defaultValue={moment(new Date()).format('YYYY-MM-DD hh:mm:ss')} />
        <TextInput disabled label="Agent Name" defaultValue={sessionStorage.getItem('foneBookUser')} source="CreatedBy" />
        <TextInput label="First Name" defaultValue={'Adam'} source="FirstName" validate={validateLength} />
        <TextInput label="Surname" defaultValue={'Smith'} source="Surname" validate={validateLength} />
        <TextInput label="RSA ID Number" defaultValue={4567890987654} source="IDNumber" validate={validateID} />
        <SelectInput label="Sex" defaultValue={'M'} source="sex" choices={[
            { id: 'M', name: 'Male' },
            { id: 'F', name: 'Female' },
        ]} validate={validateSex}/>
        <TextInput label="Age of Applicant" defaultValue={45} source="ApplicantAge" validate={validateAge} />
        <TextInput label="Business Partner" defaultValue={''} source="BusinessPartner" />
        <TextInput label="Sales Person" defaultValue={'Spiderman'} source="SalesPerson" validate={validateLength} />
        <TextInput label="Cell Phone Number" defaultValue={'345678'} source="CellNumber" validate={validateLength} />
        <TextInput label="Email Address" defaultValue={'adam@email.com'} source="Email" validate={validateEmail} />
      </FormTab>
      <FormTab label="bureau">
        <TextInput label="Bureau Score" defaultValue={123} source="BureauScore" validate={validateBureauScore} />
        <TextInput label="Gross Monthly Income" defaultValue={30000} source="GrossMonthlyIncome" validate={validateGross} />
        <TextInput label="Total Monthly Instalment" defaultValue={3000} source="TotalMonthlyInstalment" validate={validateInstal} />
        <TextInput label="Home Postcode" defaultValue={'1122'} source="HomePostCode" validate={validateCode} />
        <TextInput label="Number of Properties" defaultValue={11} source="NumProperties" validate={validateNumber} />
        <TextInput label="Number of Companies" defaultValue={31} source="NumCompanies" validate={validateNumber} />
      </FormTab>
    </TabbedForm>
  </Create>
);

VetEdit
export const VetEdit = props => {
  const classes = useStyles();
  return (
    <Edit aside={<EditAside />} {...props}>
        <SimpleForm toolbar={<VetEditToolbar />} warnWhenUnsavedChanges>
          <TextInput disabled label="First Name" source="FirstName" formClassName={classes.inlineBlock} />
          <TextInput disabled label="Surname" source="Surname" formClassName={classes.inlineBlock} />
          <TextInput disabled label="RSA ID Number" source="IDNumber" formClassName={classes.inlineBlock} />
          <TextInput disabled source="Sex" formClassName={classes.inlineBlock} />
          <NumberInput disabled source="ApplicantAge" formClassName={classes.inlineBlock} />
          <TextInput disabled source="CellNumber" formClassName={classes.inlineBlock} />
          <TextInput disabled source="Email" formClassName={classes.inlineBlock} />
          <TextInput disabled source="BusinessPartner" formClassName={classes.inlineBlock} />
          <TextInput disabled source="SalesPerson" formClassName={classes.inlineBlock} />
          <TextInput disabled source="HomePostCode" formClassName={classes.inlineBlock} />
          <NumberInput disabled source="NumProperties" formClassName={classes.inlineBlock} />
          <NumberInput disabled source="NumCompanies" formClassName={classes.inlineBlock} />

          <NumberInput disabled source="GrossMonthlyIncome" formClassName={classes.inlineBlock} />
          <NumberInput disabled source="TotalMonthlyInstalment" formClassName={classes.inlineBlock} />
          <NumberInput disabled source="BureauScore" formClassName={classes.inlineBlock} />

          <SelectInput label="ID Verified" source="IDVerified" choices={[
            { id: 'N', name: 'No' },
            { id: 'Y', name: 'Yes'}
          ]} formClassName={classes.inlineBlock} />
          <SelectInput label="Debt Review" source="DebtReview" choices={[
            { id: 'N', name: 'No' },
            { id: 'Y', name: 'Yes'}
          ]} formClassName={classes.inlineBlock} />
          <SelectInput label="Poor Payment Profile" source="PoorPaymentProfile" choices={[
            { id: 'N', name: 'No' },
            { id: 'Y', name: 'Yes'}
          ]} formClassName={classes.inlineBlock} />
          <SelectInput label="Adverse" source="Adverse" choices={[
            { id: 'N', name: 'No' },
            { id: 'Y', name: 'Yes'}
          ]} formClassName={classes.inlineBlock} />
          <SelectInput label="Fraud Suspected" source="SuspectFraud" choices={[
            { id: 'N', name: 'No' },
            { id: 'Y', name: 'Yes'}
          ]} formClassName={classes.inlineBlock} />

          <TextInput label="ID Validated" source="IDValidated" formClassName={classes.inlineBlock} />
          <TextInput label="Bank Statement Validated" source="BankStatementValidated" formClassName={classes.inlineBlock} />
          <TextInput label="Payslip Validated" source="PayslipValidated" formClassName={classes.inlineBlock} />
          <TextInput label="Proof of Residence Validated" source="ResProofValidated" formClassName={classes.inlineBlock} />
        </SimpleForm>
    </Edit>
  )
};

DataProvider.js
import { fetchUtils } from 'react-admin';
import { stringify } from 'query-string';

const apiUrl = 'http://localhost:8081';

const httpClient = (url, options = {}) => {
    if (!options.headers) {
        options.headers = new Headers({
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        });
    }
    // add your own headers here
    options.headers.set(
      'X-Custom-Header',
      'Access-Control-Allow-Headers',
      'Access-Control-Allow-Origin',
      '*',
    );
    //console.log('4 options: ', options);
    return fetchUtils.fetchJson(url, options);
};

export default {
  getList: (resource, params) => {
    //console.log('params: ', params);
      const { page, perPage } = params.pagination;
      const { field, order } = params.sort;
      const query = {
          sort: JSON.stringify([field, order]),
          range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
          filter: JSON.stringify(params.filter),
      };
      const url = `${apiUrl}/${resource}?${stringify(query)}`;
      //console.log('url: ', url);

      return httpClient(url).then(({ headers, json }) => ({
          data: json,
          total: parseInt(headers.get('content-range').split('/').pop(), 10),
      }));
  },

  getOne: (resource, params) =>
        httpClient(`${apiUrl}/${resource}/${params.id}`).then(({ json }) => ({
            data: json,
        })),

    getMany: (resource, params) => {
        const query = {
            filter: JSON.stringify({ id: params.ids }),
        };
        const url = `${apiUrl}/${resource}?${stringify(query)}`;
        return httpClient(url).then(({ json }) => ({ data: json }));
    },

    getManyReference: (resource, params) => {
        const { page, perPage } = params.pagination;
        const { field, order } = params.sort;
        const query = {
            sort: JSON.stringify([field, order]),
            range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
            filter: JSON.stringify({
                ...params.filter,
                [params.target]: params.id,
            }),
        };
        const url = `${apiUrl}/${resource}?${stringify(query)}`;

        return httpClient(url).then(({ headers, json }) => ({
            data: json,
            total: parseInt(headers.get('content-range').split('/').pop(), 10),
        }));
    },

    update: (resource, params) =>
        httpClient(`${apiUrl}/${resource}/${params.id}`, {
            method: 'PUT',
            body: JSON.stringify(params.data),
        }).then(({ json }) => ({ data: json })),

    updateMany: (resource, params) => {
        const query = {
            filter: JSON.stringify({ id: params.ids}),
        };
        return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
            method: 'PUT',
            body: JSON.stringify(params.data),
        }).then(({ json }) => ({ data: json }));
    },

    create: (resource, params) =>
        httpClient(`${apiUrl}/${resource}`, {
            method: 'POST',
            body: JSON.stringify(params.data),
        }).then(({ json }) => ({
            data: { ...params.data, id: json.id },
        })),

    delete: (resource, params) =>
        httpClient(`${apiUrl}/${resource}/${params.id}`, {
            method: 'DELETE',
        }).then(({ json }) => ({ data: json })),

    deleteMany: (resource, params) => {
        const query = {
            filter: JSON.stringify({ id: params.ids}),
        };
        return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
            method: 'DELETE',
            body: JSON.stringify(params.data),
        }).then(({ json }) => ({ data: json }));
    }
};

Vet API
Vet.createVet = async function(newVet, result) {
  console.log('newVet: ', newVet);
  await sql.query("INSERT INTO vets set ?", newVet, function(err, res) {
    if(err) {
      console.log('err: ', err);
      result(err, null);
    } else {
      console.log('res.insertId: ', res.insertId);
      result(null, res.insertId)
    }
  });
};

Vet.getVetById = async function (VetId, result) {
  console.log('getVetById: ', VetId);
  await sql.query("Select * from vets WHERE id = ?", VetId, function (err, res) {
    if(err) {
      console.log("error: ", err);
      result(null, err);
    } else {
      console.log('vets : ', res);
      result(null, res);
    }
  });
};

await 只有当你 await 承诺时才会做一些有用的事情。像这样的语句:

await sql.query("INSERT INTO vets set ?", newVet, function(err, res) {...});

不等待承诺。该查询没有 return 承诺。该操作的结果仅出现在该回调中,而不出现在任何 returned promise 中,因此 await 无关。 await 中没有魔法可以知道普通回调何时完成。不,await 以承诺为基础运作,如果你不给它承诺,它就无事可做(不等待任何事情)。

相反,您需要使用不使用回调的数据库操作,而是 return promises 如果您想对它们使用 await

如果您正在使用 mysql,请参阅 mysql2 以获取承诺支持,然后重写所有数据库语句以使用 returned 承诺从中获取结果并且不通过数据库调用一个简单的回调。

万一其他人遇到这个问题并且不知道 promise - async/await 关系,我发现 this 文章非常有帮助。