简体   繁体   English

从不同的组件设置状态

[英]setting state from a different component

First of all, my approach could just be misguided from the start.首先,我的方法可能从一开始就被误导了。

I have a component that lists objects added by a sibling component.我有一个组件列出了由同级组件添加的对象。

I would like the list component to update when a new object is added.我希望在添加新对象时更新列表组件。

As you can see, I'm calling the same function (getHostedServiceList) in both components.如您所见,我在两个组件中调用了相同的函数 (getHostedServiceList)。 Obviously, this would need t be cleaned up, but I'd like to get it working first显然,这不需要清理,但我想先让它工作

I'm using hooks to accomplish this.我正在使用钩子来实现这一点。

//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>
  );
};

I would like the list component to update when a new object is added.我希望在添加新对象时更新列表组件。

This is where something like Redux or MobX comes in handy.这就是ReduxMobX 之类的东西派上用场的地方。 These tools allow you to create a "store" - the place where you load and store data used by different components throughout your app.这些工具允许您创建一个“存储”——您可以在该位置加载和存储整个应用程序中不同组件使用的数据。 You then connect your store to individual components which interact with the data (displaying a list, displaying a create/edit form, etc).然后,您将商店连接到与数据交互的各个组件(显示列表、显示创建/编辑表单等)。 Whenever one component modifies the data, all other components will receive the updates automatically.每当一个组件修改数据时,所有其他组件都会自动接收更新。

One way this cross-communication is accomplished is through apub/sub mechanism - whenever one component creates or modifies data, it publishes (or "dispatches") an event.实现这种交叉通信的一种方式是通过发布/订阅机制——每当一个组件创建或修改数据时,它就会发布(或“调度”)一个事件。 Other components subscribe (or "listen") for these events and react (or "re-render") accordingly.其他组件订阅(或“监听”)这些事件并相应地做出反应(或“重新渲染”)。 I will leave the research and implementation up to the reader as it cannot be quickly summarized in a StackOverflow answer.我将把研究和实现留给读者,因为它无法在 StackOverflow 答案中快速总结。

You might also try the new React hooks , as this allows you to easily share data between components.您也可以尝试新的React hooks ,因为这允许您轻松地在组件之间共享数据。 If you choose this option, please take special care to do it properly as it is easy to be lazy and irresponsible.如果您选择此选项,请特别注意正确操作,因为它很容易偷懒和不负责任。

To get you started, here are some articles to read.为了让您开始,这里有一些文章供您阅读。 I highly recommend reading the first one:我强烈推荐阅读第一篇:

Yes, you could use Redux (or React's own 'context') for global state handling.是的,您可以使用 Redux(或 React 自己的“上下文”)进行全局状态处理。 However, a simpler solution to be considered might just be to send the data to the parent and pass to the list component like so:但是,要考虑的更简单的解决方案可能只是将数据发送到父级并传递给列表组件,如下所示:

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>
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM