Почему я получаю ошибку componentWillReact от Mobx? - PullRequest
0 голосов
/ 07 октября 2019

Недавно столкнулся с ошибкой при использовании React + Mobx. Я знаю, что ошибка была устранена в mobx-react@6.0.0, но теперь я вижу ее снова. Я нашел способ обойти это, но я чувствую, что он делает слишком много компромиссов с точки зрения читабельности и структуры кода.

Вот что я вижу:

При использовании mobx я могу создать store и пометьте некоторые элементы данных как @observable, чтобы указать, что за ними нужно следить за изменениями. В соответствии с этими документами, я должен затем поместить @observer и @inject(...) в компонент, который читает эти значения, и все будет правильно восстановлено.

Например, мой магазин Patient.store.ts :

import { observable, action, computed } from 'mobx';

import patientsList from '../../dummy-data/patients.json';

interface Patient {
  firstName: string;
  lastName: string;
  gender: string;
  age: number;
  id: string;
  guid: string;
}

export class PatientsStore {
  @observable patients: Patient[] = [];
  @observable selectedPatient?: Patient;

  constructor() {
    this.loadPatients();
  }

  loadPatients() {
    const res = patientsList.patients; // will come from an API when the API is ready
    this.setPatients(res);
  }

  @action('SET_PATIENTS')
  setPatients(data: Patient[]) {
    this.patients = data;
  }

  @action('SELECT_PATIENT')
  selectPatient(patientId: string) {
    const selectedPatient = this.patients.find(patient => patient.id === patientId);
    if (selectedPatient) {
      this.selectedPatient = selectedPatient;
    }
  }
}

const patientsStore = new PatientsStore();
export default patientsStore; // Create a singleton

И мой компонент класса PatientsList.tsx :

@inject('patientsStore')
@observer
class PatientsList extends React.Component<PatientsListProps, PatientsListState> {
  constructor(props: {}) {
    super(props);

    this.state = { collapsed: false };
  }

  getMenuItems = () => {
    return this.props.patientsStore!.patients.map((patient: Patient) => {
      return (
        <Menu.Item key={patient.id}>
          <Icon type={patient.gender === 'male' ? 'man' : 'woman'} />
          <span className='patient-name'>
            {patient.lastName}, {patient.firstName}
          </span>
        </Menu.Item>
      );
    });
  };

  render() {
    const menuItems = this.getMenuItems();

    return (
      <Sider
        breakpoint='md'
        collapsedWidth='0'
        style={{
          overflow: 'auto',
          height: '100vh',
          position: 'fixed',
          left: 0,
        }}
      >
        <Menu mode='inline'>{menuItems}</Menu>
      </Sider>
    );
  }
}

export default PatientsList;

Вопрос в том, когда я делаю это таким образом (используя этот компонент класса), В браузере появляется сообщение об ошибке Cannot read property componentWillReact of undefined. Но, когда я переписываю компонент как забавный функциональный компонент, я не получаю ошибки, и он отображается так, как ожидалось:

import React from 'react';
import { Layout, Menu, Icon } from 'antd';
import { Patient } from '../interfaces/Patient';
import { inject, observer } from 'mobx-react';
import patientsStore, { PatientsStore } from '../stores/patients.store';

const { Sider } = Layout;

interface PatientsListProps {
  patientsStore?: PatientsStore;
}

const handleClick = (patientId: string) => {
  patientsStore.selectPatient(patientId);
};

const getMenuItems = (patients: Patient[]) => {
  return patients.map((patient: Patient) => {
    return (
      <Menu.Item key={patient.id} onClick={() => handleClick(patient.id)}>
        <Icon type={patient.gender === 'male' ? 'man' : 'woman'} />
        <span className='patient-name'>
          {patient.lastName}, {patient.firstName}
        </span>
      </Menu.Item>
    );
  });
};

export const PatientsList = inject('patientsStore')(
  observer((props: PatientsListProps) => (
    <Sider
      breakpoint='md'
      collapsedWidth='0'
      style={{
        overflow: 'auto',
        height: '100vh',
        position: 'fixed',
        left: 0,
      }}
    >
      <Menu mode='inline'>{getMenuItems(props.patientsStore!.patients)}</Menu>
    </Sider>
  ))
);

Почему я вижу эту ошибку? Почему аннотации работают в магазине, а не в компоненте? Есть ли лучший способ написать компонент, который будет так же удобен для чтения, как и аннотации?

Соответствующие версии:

{
    "mobx": "^5.14.0",
    "mobx-react": "^6.1.3",
    "react": "^16.9.0"
}
...