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

Posted

技术标签:

【中文标题】在相邻组件之间共享内容,HOC?【英文标题】:Sharing content between adjacent components, HOC? 【发布时间】:2019-07-16 17:50:48 【问题描述】:

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

我想渲染一些额外的内容(DOM 元素/其他反应组件)内部较低的组件,但额外的内容是在顶部组件内创建的。我正在努力弄清楚我需要在这里重构什么才能完成这项工作。我最初尝试将创建的内容传递给容器,然后返回到较低的组件。我很快意识到这不起作用,因为创建的内容依赖于创建它的组件的道具/状态。

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

我对 React 还很陌生,所以我很难尝试用 react 方式解决这个问题。我已经简要了解了渲染道具/HOC,也许这就是我需要的?任何帮助将不胜感激。

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

【问题讨论】:

您可以提升状态和/或创建 jsx 并将其作为道具传递。你不需要 hocs 也不需要 renderprops 是的,就像@victor.ja 提到的那样,您需要提升组件的状态。他指给你的文章是你能得到的最好的解释:reactjs.org/docs/lifting-state-up.html阅读后回访,如果你仍然不确定如何解决这个问题,我们可以举个例子。 【参考方案1】:

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

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

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

我们将拥有一个 Container 组件。该组件将是一个有状态的组件。这个 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>
    );
  

如你所见,容器只有一个状态,一些更新状态的方法和子组件。在其渲染方法中没有使用一个 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>
  );

这个组件就像一个表单(我懒得用表单和 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>
  );

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

我为你创建了一个代码框,以防你想玩这个功能,你看看最终结果https://codesandbox.io/s/04rowq150

因此,通过这种方式,您不必在 Container 内创建任何内容,而是可以使用 Container 作为指导,通过定义初始状态和几个方法来传递其子级以允许它们创建新内容,并代表Container显示这些新创建的内容

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

【讨论】:

【参考方案2】:

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

更多信息:lifting state

——————

一个

/\

B C

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

【讨论】:

【参考方案3】:

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

【讨论】:

以上是关于在相邻组件之间共享内容,HOC?的主要内容,如果未能解决你的问题,请参考以下文章

组件之间数据共享

Angular 2以组件为属性的共享组件

在所有 vue 组件实例之间共享变量

在同一层级子组件之间共享存储更改事件

如何在 VueJS 中的组件之间共享数据

Ng2 通过服务在组件之间共享数据