在2个React DOM之间传递数据

时间:2018-04-25 13:48:35

标签: javascript reactjs redux react-dom

在网站中,我有多个反应渲染元素。我想在这两个单独的元素之间传递数据。在两个元素之间传递数据的可能选项是什么

ReactDOM.render(<Header/>, document.getElementById('header'));
ReactDOM.render(<SideBar/>, document.getElementById('sidebar'));

我想在这些元素之间存储单个数据。就像我在一个组件中获取数据一样,我希望所有元素都可以访问这些数据(在所有ReactDOM中)。 那么可能的选择是什么呢?

编辑:由于要求,我无法将它们合并到同一根组件中。只有页面的某些部分处于反应中,其他部分仍在HTML / Jquery中。所以我在所需的div中单独渲染它们。

redux存储在不同的ReactDOM之间工作吗?

5 个答案:

答案 0 :(得分:5)

您可以创建一个组件容器,并将它们作为子项并将它们分开。通过道具和母容器交换数据。

我举了一个例子:

https://codepen.io/hkares/pen/rvLPzQ

HTML

//html
<header id="header"></header>
<main>
  <nav id="nav"></nav>
  <section>I am section</section>
</main>
<footer>This is a footer</footer>
<div id="useless"></div>

Index.js

const HEADER_NODE = document.querySelector("#header");
const NAVBAR_NODE = document.querySelector("#nav");

const Header = ({ name }) => ReactDOM.createPortal(<h1>{name}</h1>, HEADER_NODE);

const NavBar = (props) => ReactDOM.createPortal(
  <article>
    <label>
      Set header name: <input {...props} />
    </label>
  </article>
, NAVBAR_NODE);

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: "this is a header"
    };
  }

  onChange = ({ target }) => this.setState({ value: target.value });

  render() {
    const { value } = this.state;
    return (
      <React.Fragment>
        <Header name={value} />
        <NavBar value={value} onChange={this.onChange} />
      </React.Fragment>
    );
  }
}

ReactDOM.render(
  <Container />,
  document.querySelector("#useless")
);

答案 1 :(得分:3)

使用react-dom库中的Portals

  

Portals提供了一种将子项呈现为存在于父组件的DOM层次结构之外的DOM节点的第一类方法。

const HeaderPortal = ReactDOM.createPortal(<Header />, document.getElementById('header'))
const SideBarPortal = ReactDOM.createPortal(<SideBar />, document.getElementById('sidebar'))

const store = createStore(/* ... */)

ReactDOM.render(
  <YourDataStoreProvider store={store}>
    <HeaderPortal />
    <SideBarPortal />
  </YourDataStoreProvider>, 
  document.getElementById('root') // assuming you have an empty "dummy" node with that id
);

只需将应用程序渲染到DOM中任何位置的容器中,或者创建一个新的“虚拟”节点。在我的示例中,我假设有一个标识为root的空节点。然后将其他组件呈现为门户。

  

redux store是否可以在不同的ReactDOM之间工作?

您的应用就像完全呈现在同一个容器中一样。如果使用Portals,则组件将在具有相同上下文的同一组件树中,同时在其他位置呈现。

我应该使用门户吗?

使用门户通常用于视觉上需要“打破”其容器的组件,如模态或对话框。但您也可以使用它们来创建可在任何地方呈现的类似于小部件的组件。

创建通用Portal组件

您还可以创建一个通用<Portal>组件,该组件在给定容器id的情况下创建门户网站:

import {createPortal} from 'react-dom';

const Portal = ({children, container}) => createPortal(
    children,
    document.getElementById(container),
);

export default Portal;

并以这种方式使用它:

ReactDOM.render(
  <YourDataStoreProvider store={store}>
    <Portal container="header">
      <Header />
    </Portal>
    <Portal container="sidebar">
      <SideBar />
    </Portal>
  </YourDataStoreProvider>, 
  document.getElementById('root')
);

修改

您需要在DOM中使用一个节点来渲染您的应用。这可以是您创建的新DOM元素,也可以是您已拥有的容器之一。鉴于您使用上面的<Portal>组件,它也可能如下所示:

ReactDOM.render(
    <YourDataStoreProvider store={store}>
        <Header /> // this will be visible in your header container
        <Portal container="sidebar">
            <SideBar /> // this will be rendered to the sidebar container
        </Portal>
    </YourDataStoreProvider>, 
    document.getElementById('header')
);

这会在header容器中呈现您的应用。但只有您的<Header>组件实际上在该容器中具有DOM表示。侧边栏将由门户网站呈现在sidebar容器中。但他们仍将共享相同的反应组件树并拥有相同的商店提供商。

答案 2 :(得分:0)

容器组件

    class App extends React.Component{


    render(){
var data=[];
    return(<span>
     <Header data={data}/>
        <SideBar data={data}/>
        </span>);
    }

}

答案 3 :(得分:0)

取决于两个组件之间的关系。

场景我:如果他们只是兄弟姐妹,那么你可以将它们包装在你的容器组件中或只是一个简单的,并将道具传递给孩子,如

Public Function PressEnter()
    Set WshShell = CreateObject("WScript.Shell")
    Wait(1)
    WshShell.SendKeys "{ENTER}"
    Set WshShell = Nothing
End Function

<div>
   <HeaderPortal data={yourSharedData}/>
   <SideBarPortal data={yourSharedData}/>
</div>

然后在 <YourContainer> <HeaderPortal /> <SideBarPortal/> </YourContainer> 中,您可以定义共享数据,并将其添加到您的每个孩子中

YourContainer

场景II 如果这两个组件相距很远 enter image description here 与上述类似,您希望在2到12之间共享数据,然后您应该使用render(){ <div> {children.map(child=> React.cloneElement(child, { data: yourSharedData })} </div> } 存储来共享数据,这是管理组件状态的中心位置,并通过{将其任何部分共享到所需组件{1}},您可以找到更多详情here

答案 4 :(得分:0)

构建上下文系统:

  • 上下文是存储数据的对象。
  • 模块可以在上下文中访问和更新数据。
  • 当更新上下文中的数据时,可以通知模块。
  • 取决于您的需要,模块可以自由地将数据添加到上下文,或限制为仅更新现有数据。

这不是特定的反应问题。

上下文系统的一个例子如下:

<强> content.js

System.out.println(stackTraceElements[stackTraceElements.length - 1].getClassName());

<强>用法

import uniqueId from 'lodash/uniqueId';

let context = {
  foo: '',
  bar: ''
};

let listeners = {
  // key: [{ id, callback }]
};

let getAppContext = function(key) {
  return context[key];
};

let updateAppContext = function(key, value) {
  if (!context.hasOwnProperty(key)) {
    throw new Error(
      `Failed to update appContenxt: "${key}" does not exist.`
    );
  }

  let oldValue = context[key];
  context[key] = value;
  let callbacks = listeners[key];
  if (callbacks !== undefined && callbacks.length !== 0) {
    callbacks.forEach(function(item) {
      item.callback(value, oldValue);
    });
  }
};

let onAppContextUpdate = function(key, callback) {
  if (!context.hasOwnProperty(key)) {
    throw new Error(
      `Failed to add listener on appContenxt update: "${key}" does not exist.`
    );
  }

  if (listeners[key] === undefined) {
    listeners[key] = [];
  }

  let isListening = true;
  let id = uniqueId();
  listeners[key].push({ id, callback });

  return function removeListener() {
    if (isListening) {
      listeners[key] = listeners[key].filter(i => i.id !== id);
      isListening = false;
    }
  };
};

export {
  getAppContext,
  updateAppContext,
  onAppContextUpdate,
};