如何在ReactJS中的子组件(兄弟姐妹)之间共享状态?

时间:2018-12-06 09:54:32

标签: javascript reactjs gatsby

我想将状态传递给兄弟姐妹甚至祖父母。

我有3个组成部分。在Header内部,我有一个带有onClick功能的按钮,用于切换Navigation内部的下拉菜单。顺便说一句,我想将相同的状态传递给AnotherComponent

如何将状态(例如isDropdownOpened)从Header传递到NavigationAnotherComponent

<div>
     <Header />
       <Navigation />
        <div>
          <div>
             <div>
               <AnotherComponent />
             </div>
           </div>
        </div>
</div>

6 个答案:

答案 0 :(得分:5)

您有不同的方法来解决这种情况。

  • 将状态保留在顶部,并通过道具将其传递给孩子
  • 使用状态容器在各个组件(例如https://redux.js.org/)之间保持和共享您的应用程序状态
  • 使用新的React Context功能。上下文提供了一种通过组件树传递数据的方法,而不必在每个级别手动传递道具。

答案 1 :(得分:2)

  

如何将状态(例如isDropdownOpened)从Header传递到NavigationAnotherComponent

您将状态保留在Header的祖先中,并将该状态作为道具传递给HaeaderNavigationAnotherComponent。请参阅文档中的State and LifecycleLifting State Up

示例:

const Header = props => (
    <div>
        <span>Header: </span>
        {props.isDropdownOpened ? "Open" : "Closed"}
    </div>
);

const Navigation = props => (
    <div>
        <span>Navigation: </span>
        {props.isDropdownOpened ? "Open" : "Closed"}
    </div>
);

const AnotherComponent = props => (
    <div>
        <span>AnotherComponent: </span>
        {props.isDropdownOpened ? "Open" : "Closed"}
    </div>
);

class Wrapper extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          isDropdownOpened: false
        };
    }
    componentDidMount() {
        setInterval(() => {
            this.setState(({isDropdownOpened}) => {
                isDropdownOpened = !isDropdownOpened;
                return {isDropdownOpened};
            });
        }, 1200);
    }
    render() {
        const {isDropdownOpened} = this.state;
        return (
            <div>
              <Header isDropdownOpened={isDropdownOpened} />
              <Navigation isDropdownOpened={isDropdownOpened} />
              <div>
                 <div>
                     <div>
                          <AnotherComponent isDropdownOpened={isDropdownOpened} />
                     </div>
                 </div>
              </div>
          </div>
        );
    }
}

ReactDOM.render(
    <Wrapper />,
    document.getElementById("root")
);
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>


Arnaudhis answer中提供了一些其他选项。

答案 2 :(得分:2)

就像TJ所说的那样,使用父组件的状态。这样,所有子组件都共享一个状态,这就是我想要的。

class ExampleParentComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
        isDropdownOpened: false
    }
  }

  toggleDropdown() {
    this.setState({
        isDropdownOpened: !isDropdownOpened
    });
  }

  render() {
    return (
        <div>
          <Header open={isDropdownOpened} toggleDropdown={ this.toggleDropdown }/>
          <Navigation open={ isDropdownOpened}/>
          <div>
             <div>
                 <div>
                      <AnotherComponent open={ isDropdownOpened} />
                 </div>
             </div>
          </div>
        </div>
    );
}


class Header extends React.Component {
    render() {
        return (
            <div>
                <button onClick={ this.props.toggleDropdown }>TOGGLE ME</button>
                { isDropdownOpened && (
                    <h1> DROPPED </h1>
                }
            </div>
        );
    }
}

答案 3 :(得分:2)

这就是"React Hooks"已被开发(并被社区大肆宣传)的确切原因,但尚未在生产中使用它们,它们仍处于早期开发阶段(alpha)及其规范/实现可能会改变!

您可以使用令人敬畏的“React Context“ API来解决您的问题,该API允许将数据传递到组件中,而不管它们嵌套在树中的深度如何。 要了解上下文,请阅读上面链接的大量文档。我只在这里解释一个小而快速的示例:

  1. 创建上下文组件并导出使用者

App.jsx

import React from "react";

// The initial value can be anything, e.g. primitives, object, function,
// components, whatever...
// Note that this is not required, but prevebents errors and can be used as
// fallback value.
const MyContext = React.createContext("anything");

// This component is the so called "consumer" that'll provide the values passed
// to the context component. This is not necessary, but simplifies the usage and
// hides the underlying implementation.
const MyContextConsumer = MyContext.Consumer;

const someData = { title: "Hello World" };

const App = ({ children }) => (
  <MyContext.Provider value={someData}>{children}</MyContext.Provider>
);

export { MyContextConsumer };
export default App;
  1. 将创建的使用者导入任何组件并使用提供的值

AnotherComponent.jsx

import React from "react";
import { MyContextConsumer } from "./App";

const AnotherComponent = () => (
  <div>
    <MyContextConsumer>{({ title }) => <h1>{title}</h1>}</MyContextConsumer>
  </div>
);

export default AnotherComponent;
  1. 使用两个上下文组件呈现应用程序
import React from "react";
import ReactDOM from "react-dom";

import App from "./App";
import AnotherComponent from "./AnotherComponent";

const Root = () => (
  <App>
    <AnotherComponent />
  </App>
);

const rootElement = document.getElementById("root");
ReactDOM.render(<Root />, rootElement);

该组件将使用“ Hello World”文本呈现第1级标题。

Edit stackoverflow-53648661-how-to-share-state-between-child-component-siblings-in-reactjs

答案 4 :(得分:0)

您只能使用this.state.variableName来访问

<ChildComponent data={this.state.name} />

并传递函数

<ChildComponent data={this.HandleChange} />

答案 5 :(得分:-1)

First Send the data from the first child to the common parent using callback 
function and then send that received data (stored in state in parent component)
to the second child as props.

您还可以阅读这篇文章-https://www.pluralsight.com/guides/react-communicating-between-components