相邻组件之间共享内容,HOC?

Sharing content between adjacent components, HOC?

我有一个容器组件,它在其中呈现两个组件。根据容器中的一些道具,顶部组件可以改变,但底部组件将始终保持不变。

我想渲染一些额外的内容(DOM elements/other react 组件) 较低的组件中,但是额外的内容是在顶部创建的零件。我正在努力弄清楚我需要在这里重构什么才能完成这项工作。我最初尝试将创建的内容向上传递到容器,然后返回到下层组件。我很快意识到这不起作用,因为创建的内容依赖于创建它的组件的 props/state。

在容器内创建内容是不可行的,因为对于可以创建的内容有很多不同的选择。我正在处理的代码库有 30-40 个可能的组件,它们都会生成不同的内容。

我是 React 的新手,所以我在尝试以 React 方式解决这个问题时遇到了困难。我已经简要阅读了有关 render props/HOCs 的内容,也许这就是我在这里需要的?任何帮助将不胜感激。

这是一个非常基本的示例:https://codesandbox.io/s/zqo2p1yy9m

反应的本质是top/down。因此,如果您需要共享一部分状态或一些数据以作为 props 传递,则需要将该代码提升到其父级。 把 Jsx 作为 props 传递是可以的,这里你需要这样做,你可以。

更多信息:lifting state

————————

一个

/ \

B C

因此,如果您在 B 和 C 之间共享代码,您可以将其提升到 A 并将其作为 props 传递给 B 和 C。 如果您需要 B 在 C 处的状态,则将状态提升到 A。 如果您需要在 B 或 C 访问和修改 A 的状态,只需将函数作为回调传递给 B 或 C

我同意 victor.ja 但我想知道你是否有像 redux 这样的全球商店。然后,您只需调用操作即可从顶级组件更新商店的状态。高阶组件可以接收商店的状态作为道具并更新低阶组件。

有几种方法可以解决这个问题

1) 可以使用Redux、mobx等状态管理系统,也可以使用React的context API https://reactjs.org/docs/context.html。但是,由于您是 React 的新手,我建议您在熟悉基本流程之前不要处理这些正确的知识

2) 您可以实现一个简单的 parent-child relationship 来在组件之间传递数据。最终,这允许您提供相邻(兄弟)组件之间的通信。如前所述,这种流动通常被称为提升状态。实际上,状态管理系统以类似的方式工作。让我通过考虑您基于场景的代码示例来解释这个逻辑。

我们将有一个容器组件。该组件将是一个有状态组件。这个 Container 组件的唯一目的是拥有它自己的整体状态,它的 children 会将其视为真实的来源。有几种方法来定义更新这种整体状态的方法。 children 组件将是纯组件,或代表性组件。这意味着,他们不会有自己的状态。它们将用于显示它们的 parent 传递给它们的数据或触发由它们的 parent 定义的方法以更新真实状态的来源。

我们将有两种情况: 在场景 1 中,内容列表将按原样表示。 在场景2中,内容列表将通过颠倒字母顺序来表示

class Container extends React.PureComponent {
  state = {
    reversed: false,
    newContent: "",
    contents: [
      {
        id: 1,
        text: "Initial Content"
      }
    ]
  };

  handleReverse = () => {
    this.setState((state) => ({
      ...state,
      reversed: !state.reversed
    }))
  }
  submitNewContent = () => {
    this.setState(state => ({
      ...state,
      contents: [
        ...state.contents,
        { id: Math.random(), text: state.newContent }
      ],
      newContent: ""
    }));
  };
  addNewContent = content => {
    this.setState({ newContent: content });
  };

  render() {
    return (
      <React.Fragment>
        <ContentCreator
        value={this.state.newContent}
        handleChange={this.addNewContent}
        handleClick={this.submitNewContent}
        />
        {this.state.reversed ? <ReversedContentDisplayer contents={this.state.contents} /> : <ContentDisplayer contents={this.state.contents} />}
        <Reversifier reversed={this.state.reversed} handleReverse={this.handleReverse}/>
      </React.Fragment>
    );
  }
}

如你所见,容器只有一个状态,一些更新状态的方法和child组件。没有一个 html 在其 render 方法中使用。

我们的第一个 child 组件是 ContentCreator

function ContentCreator({
  handleChange,
  handleClick,
  value
  }) {
  return (
    <div className="App">
      <label> New Content</label>
      <input type="text" value={value} onChange={event => handleChange(event.target.value)} />
      <button onClick={handleClick}>Add Content</button>
    </div>
  );
}

这个组件就像一个表单(我懒得用表单和 onSubmit 函数包装它)。这个组件的主要目的是更新我们的真实来源状态

contents

第二部分叫做Reversifier(虽然我不相信有这个词)

function Reversifier({reversed, handleReverse}) {
  return <button onClick={handleReverse}>{reversed ? 'Back to normal' : 'Reversify'}</button>
}

此组件的主要目的是切换 reversed 我们的真实状态源的关键。您还可以看到,根据 reversed 的值,按钮内的文本也会发生变化(以不同的方式反映不同的场景)

最后两个组件是

function ContentCreator({
  handleChange,
  handleClick,
  value
  }) {
  return (
    <div className="App">
      <label> New Content</label>
      <input type="text" value={value} onChange={event => handleChange(event.target.value)} />
      <button onClick={handleClick}>Add Content</button>
    </div>
  );
}

function ReversedContentDisplayer({ contents }) {
  return (
    <div className="App">
      {contents.map(content => (
        <div key={content.id}>{content.text.split("").reverse().join("")}</div>
      ))}
    </div>
  );
}

根据场景,即显示内容是正常显示还是反转显示,在内部或我们容器组件的渲染方法中,我们显示它们中的任何一个。实际上,这两个组件可以写成一个,例如

function ContentDisplayer({ contents, reversed }) {
  return (
    <div className="App">
      {contents.map(content => (
        <div key={content.id}>{reversed ? content.text.split("").reverse().join("") : content.text}</div>
      ))}
    </div>
  );
}

但是为了反映不同的场景,我创建了两个不同的组件

我为你创建了一个 codesandbox,以防你想使用该功能你会看到最终结果 https://codesandbox.io/s/04rowq150

因此,通过这种方式,您不必在 Container 中创建任何内容,而是可以通过定义初始状态和一些方法来使用 Container 作为指南传递其 children 以允许他们创建新内容,并代表 Container

显示这些新创建的内容

我希望这个示例可以作为起点对您有所帮助,我希望我至少能正确理解您的要求 51%。如果您还有其他问题或困惑,请告诉我