установка состояния из другого компонента - PullRequest
0 голосов
/ 23 апреля 2019

Прежде всего, мой подход может быть ошибочным с самого начала.

У меня есть компонент, который перечисляет объекты, добавленные с помощью компонента-брата.

Я хотел бы обновить компонент спискакогда добавляется новый объект.

Как видите, я вызываю одну и ту же функцию (getHostedServiceList) в обоих компонентах.Очевидно, что это не нужно очищать, но я бы хотел, чтобы это сначала заработало

Для этого я использую хуки.

// input

const options = [
  { value: '1', label: '1' },
  { value: '2', label: '2' },
  { value: '3', label: '3' },
];

// class Remotes extends Component {
const Remotes = ({ ...props }) => {
  const [service, setService] = useState();
  const [url, setUrl] = useState();
  const [token, setToken] = useState();
  const [displayName, setDisplayName] = useState();
  const [apiUrl, setApiUrl] = useState();
  const [services, setServices] = useState();

  let HOME = process.env.HOME || '';
  if (process.platform === 'win32') {
    HOME = process.env.USERPROFILE || '';
  }

  const getHostedServiceList = () => {
    console.log('props', props);
    if (!fs.existsSync(`${HOME}/providers.json`)) {
      return newMessage(
        `Unable to locate ${HOME}/providers.json`,
        'error',
      );
    }
    const payload = JSON.parse(
      fs.readFileSync(`${HOME}/providers.json`),
    );

    setServices(payload);
  };

  const setProvider = selectedOption => {
    setService(selectedOption.value);
    setUrl(`http://www.${selectedOption.value}.com`);
    setApiUrl(`http://www.${selectedOption.value}.com/api/v1`);
  };

  const { onAddRemote } = props;
  return (
    <div>
      <div>Add a remote host:</div>
      <StyledSelect
        value="Select Provider"
        onChange={setProvider}
        options={options}
      />
      {console.log('service', service)}
      <TextInput
        label="Url"
        defaultValue={url}
        onChange={e => {
          setProvider(e.target.value);
        }}
        disabled={!service ? 'disabled' : ''}
      />

      <TextInput
        label="API Url"
        defaultValue={apiUrl}
        onChange={e => setApiUrl(e.target.value)}
        disabled={!service ? 'disabled' : ''}
      />

      <TextInput
        label="Token"
        onChange={e => setToken(e.target.value)}
        disabled={!service ? 'disabled' : ''}
      />

      <TextInput
        label="Display Name"
        onChange={e => setDisplayName(e.target.value)}
        disabled={!service ? 'disabled' : ''}
      />

      <Button
        disabled={!service || !url || !token}
        onClick={() => {
          onAddRemote({ service, url, apiUrl, token, displayName });
          getHostedServiceList();
        }}
      >
        Add Remote
      </Button>
    </div>
  );
};

// list


const HostedProviderList = ({ ...props }) => {
  const [services, setServices] = useState();

  let HOME = process.env.HOME || '';
  if (process.platform === 'win32') {
    HOME = process.env.USERPROFILE || '';
  }

  const getHostedServiceList = () => {
    console.log('props', props);
    if (!fs.existsSync(`${HOME}/providers.json`)) {
      return newMessage(
        `Unable to locate ${HOME}/providers.json`,
        'error',
      );
    }
    const payload = JSON.parse(
      fs.readFileSync(`${HOME}/providers.json`),
    );

    setServices(payload);
  };

  useEffect(() => {
    // console.log('props 1', services);
    getHostedServiceList();
  }, []);

  return (
    <Wrapper>
      <Flexbox>
        <Title>Provider List</Title>
      </Flexbox>
      <div>
        {services &&
          services.map((service, i) => (
            <Service key={i}>
              <ServiceName>{service.displayName}</ServiceName>
              <ServiceProvider>{service.service}</ServiceProvider>
            </Service>
          ))}
      </div>
    </Wrapper>
  );
};

Я бы хотел, чтобы компонент списка обновлялся при добавлении нового объекта.

Ответы [ 2 ]

0 голосов
/ 23 апреля 2019

Да, вы можете использовать Redux (или собственный «контекст» React) для обработки глобального состояния. Однако более простое решение, которое следует рассмотреть, может состоять в том, чтобы просто отправить данные родителю и передать компоненту списка следующим образом:

class Parent extends Component {
  state = { objectsAdded: [] }

  onObjectAdded = ( obj ) => {
    // deepclone may be needed
    this.setState({objectsAdded: this.state.objectsAdded.concat(obj)})
  }

  render() {
    return (
      <Fragment>
        <ListComponent objects={this.state.objectsAdded} />
        <ObjectAdder onObjectAdded={this.onObjectAdded} />
      </Fragment>
  }
}
0 голосов
/ 23 апреля 2019

Здесь пригодится что-то вроде Redux или MobX .Эти инструменты позволяют вам создать «хранилище» - место, где вы загружаете и храните данные, используемые различными компонентами в вашем приложении.Затем вы подключаете свой магазин к отдельным компонентам, которые взаимодействуют с данными (отображение списка, отображение формы создания / редактирования и т. Д.).Всякий раз, когда один компонент изменяет данные, все другие компоненты будут получать обновления автоматически.

Один из способов обеспечения этой перекрестной связи - через механизм pub / sub - всякий раз, когда один компонент создает или изменяетданные публикует (или «отправляет») событие.Другие компоненты подписываются (или "слушают") на эти события и реагируют (или "повторно визуализируют") соответственно.Я оставлю исследование и реализацию на усмотрение читателя, поскольку его нельзя быстро обобщить в ответе StackOverflow.

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

Для начала, вот несколько статей для чтения.Я настоятельно рекомендую прочитать первый:

...