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

时间:2019-02-22 15:34:15

标签: javascript reactjs ecmascript-6 components higher-order-components

我有一个容器组件,在其中渲染了两个组件。根据容器中的某些道具,顶部组件可以更改,但下部组件将始终保持不变。

我想在下部组件内部内部渲染一些附加内容(DOM元素/其他React组件),但是附加内容是在顶部组件内部创建的。我正在努力弄清楚在这里需要重构什么才能完成这项工作。我最初尝试将创建的内容传递到容器,然后再传递到较低的组件。我很快意识到这是行不通的,因为创建的内容依赖于创建它的组件的属性/状态。

在容器内创建内容是不可行的,因为可以创建什么内容的选择太多了。我正在处理的代码库有30-40个可能的组件,它们全部生成不同的内容。

我对React还是很陌生,所以在尝试解决React方法方面遇到困难。我已经简要阅读了有关渲染道具/ HOC的信息,也许那是我在这里需要的?任何帮助将不胜感激。

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

3 个答案:

答案 0 :(得分:1)

反应的本质是自上而下。因此,如果您需要共享一部分状态或一些数据作为道具传递,则需要将该代码提升到其父级。 可以将Jsx作为props传递,在这里您需要这样做并且可以。

更多信息:lifting state

——————

A

/ \

B C

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

答案 1 :(得分:1)

有两种方法可以解决此问题

1)您可以使用状态管理系统(例如Redux,mobx),也可以使用React的上下文API https://reactjs.org/docs/context.html。但是,由于您对React还是很陌生,所以我建议您在熟悉基本流程之前不要使用这些正确的知识来解决

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

我们将有一个容器组件。该组件将是有状态组件。此Container组件的唯一目的是拥有自己的整体状态,该状态将被其子级视为真理的来源。有两种方法来定义更新此整体状态的方法。子组件将是纯组件或代表性组件。这意味着,他们将没有自己的状态。它们要么用于显示其父级传递给他们的数据,要么触发其父级定义的方法,以更新真相状态的来源。

我们将有两种情况: 在方案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>
    );
  }
}

如您所见,容器仅具有状态,一些用于更新状态和子组件的方法。在其render方法内部未使用任何html。

我们的第一个子元素是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>
  );
}

这个组件的行为就像一个表单(我很懒,实际上是用form和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>
  );
}

根据方案,即在容器组件的render方法内部还是以常规或反向显示内容,我们将显示其中一个。实际上,这两个组件可以写成一个,例如

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

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

我为您创建了一个codeandbox,以备您使用功能时看到最终结果https://codesandbox.io/s/04rowq150

因此,通过这种方式,您不必在Container内创建任何内容,而是可以通过定义初始状态和几种方法来传递Container作为准则,允许孩子创建新内容,并代表Container

显示这些新创建的内容

我希望此样本可以为您提供一个起点,并且希望我至少理解51%的要求。如果您还有其他疑问或困惑,请告诉我

答案 2 :(得分:0)

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