Перезагрузить реагирующий компонент после обновления состояния внутри useEffect - PullRequest
0 голосов
/ 11 марта 2020

У меня есть компонент реагирования, я обновляю состояние в Mobx, и мне хотелось бы, чтобы при обновлении этого состояния перезагрузить тот же компонент. У меня есть список агентств, и я получаю агентство по типу, используя параметры запроса в одном компоненте и основываясь на параметре запроса, я хочу получить отфильтрованные данные из БД.

Код моего компонента выглядит следующим образом:

export interface IListAgenciesProps {
  agencyType: string;
  agencyTypeTitle: string;
}

const ListAgencies = (props: any) => {
  let ctx = useContext(imsStore);
  let agencies: IAgency[] = [];
  useEffect(() => {
    const agencyType = props.match.params["AgencyType"];

    ctx.setAgency(agencyType);
    async function agencyLoad(){
      await ctx.loadAgencies();
      agencies = ctx.agencies;
    }
    agencyLoad();
  }, 
  [agencies]);

  let html: JSX.Element;
  if (agencies.length > 0) {
    html = ( <Container>
        <Table celled selectable>
          <Table.Header>
            <Table.Row>
              <Table.HeaderCell>Agency Name</Table.HeaderCell>
              <Table.HeaderCell>Telephone</Table.HeaderCell>
              <Table.HeaderCell>Email</Table.HeaderCell>
              <Table.HeaderCell>Is Active?</Table.HeaderCell>
              <Table.HeaderCell>Hourly Rate</Table.HeaderCell>
            </Table.Row>
          </Table.Header>
          <Table.Body>
            {agencies.map(a => {
              return (
                <Table.Row>
                  <Table.Cell>{a.name}</Table.Cell>
                  <Table.Cell>{a.telephone}</Table.Cell>
                  <Table.Cell>{a.email}</Table.Cell>
                  <Table.Cell>{a.isActive}</Table.Cell>
                  <Table.Cell>{a.pricePerHour}</Table.Cell>
                </Table.Row>
              );
            })}
          </Table.Body>
        </Table>
      </Container>
    );
  } else {
    html = ( <Container>
        <Header as='h1'>
          Sorry, we couldn't find the agency type you're looking for.
        </Header>
      </Container>
    );
  }

  return <>{html}</>;
};

export default observer(ListAgencies);

В моем IMSStore.ts он выглядит следующим образом:

@observable agencies: IAgency[] = [];
@action loadAgencies = async () => {
    this.agencies = [];
    try {
      const agencies = await agent.Agencies.list(this.agencyType);
      agencies.forEach(agency => {
        this.agencies.push(agency);
      });
    } catch (err) {
      console.log(err);
    } finally {
    }
  };

Однако массив агентств в моем первом фрагмент кода, всегда пуст при выполнении оператора return. Поэтому каждый раз, когда запускается useEffect, он вызывает loadAgencies, а в loadAgencies оно сбрасывает значение агентств в пустой массив. Затем выполняется оператор возврата. Как сделать оператор return, чтобы дождаться, пока массив агенств не будет заполнен?

1 Ответ

1 голос
/ 12 марта 2020

Ах, хорошо, если вы хотите сохранить его относительно похожим, позвольте мне предложить возможное упрощение для вас:

export interface IListAgenciesProps {
  agencyType: string;
  agencyTypeTitle: string;
}

const ListAgencies = (props: any) => {
  const agencyType = props.match.params["AgencyType"];
  const ctx = useContext(imsStore);
  const { agencies, loadAgencies } = ctx;

  useEffect(() => {
    loadAgencies(agencyType);
  }, [agencyType]);

  let html: JSX.Element;
  if (agencies.length > 0) {
    html = ( <Container>
        <Table celled selectable>
          <Table.Header>
            <Table.Row>
              <Table.HeaderCell>Agency Name</Table.HeaderCell>
              <Table.HeaderCell>Telephone</Table.HeaderCell>
              <Table.HeaderCell>Email</Table.HeaderCell>
              <Table.HeaderCell>Is Active?</Table.HeaderCell>
              <Table.HeaderCell>Hourly Rate</Table.HeaderCell>
            </Table.Row>
          </Table.Header>
          <Table.Body>
            {agencies.map(a => {
              return (
                <Table.Row>
                  <Table.Cell>{a.name}</Table.Cell>
                  <Table.Cell>{a.telephone}</Table.Cell>
                  <Table.Cell>{a.email}</Table.Cell>
                  <Table.Cell>{a.isActive}</Table.Cell>
                  <Table.Cell>{a.pricePerHour}</Table.Cell>
                </Table.Row>
              );
            })}
          </Table.Body>
        </Table>
      </Container>
    );
  } else {
    html = ( <Container>
        <Header as='h1'>
          Sorry, we couldn't find the agency type you're looking for.
        </Header>
      </Container>
    );
  }

  return <>{html}</>;
};

export default observer(ListAgencies);

Store:

@observable agencies: IAgency[] = [];
@action loadAgencies = async (agencyType) => {
    try {
      this.agencies = await agent.Agencies.list(agencyType);
    } catch (err) {
      console.log(err);
    } finally {
    }
  };

Итак, что происходит сейчас, мы упростить компонент, чтобы сэкономить agencyType при монтировании. Затем указание его в массиве deps для эффекта означает, что мы вызываем loadAgencies каждый раз, когда изменяются параметры. Обратите внимание, что теперь мы вызываем метод ctx с параметром. Таким образом, loadAgencies будет принимать этот тип, go извлекать данные и затем устанавливать их в контекстную переменную внутри того же @action.

Затем, поскольку мы разыменовали agencies из ctx внутри компонента, он будет повторно отображаться при обновлении agencies @observable. Нам не нужно совершать вызов внутри эффекта asyn c - компонент будет перерисовываться каждый раз, когда данные возвращаются.

...