javascript - 使用 Context API 在非嵌套组件之间传递变量

标签 javascript reactjs react-context

假设我有两个未嵌套的组件:一个按钮和一个面板。单击按钮时,面板将根据之前的状态显示或隐藏(如开/关开关)。它们不是嵌套组件,因此结构如下所示:

<div>
    <Toolbar>
        <Button />
    </Toolbar>
    <Content>
        ...
        <ButtonPanel />
    </Content>
</div>

我无法更改 DOM 的结构。除了按钮和面板组件之外,我也无法修改任何其他组件。

但是,ButtonButtonPanel 组件是相关的,并且将在整个解决方案中一起使用。我需要将属性传递给面板以让它知道何时显示或何时隐藏。我正在考虑使用 Context API 来完成此操作,但我认为我做错了,并且该属性永远不会更新。

这是我的代码:

上下文

import React from 'react';

export const ButtonContext = React.createContext({
  showPanel: false,
});

按钮

import React, { Component } from 'react';
import { ButtonContext } from './ButtonContext';

class Button extends Component {
  constructor() {
    super();
    this.state = {
      showPanel: false,
    };
  }

  render() {
    return (
      <ButtonContext.Provider value={{ showPanel: this.state.showPanel }}>
        <li>
          <a
            onClick={() => this.setState({ showPanel: !this.state.showPanel }, () => console.log('Changed'))}
          >
            <span>Button</span>
          </a>
        </li>
      </ButtonContext.Provider>
    );
  }
}

export { Button };

面板

import React, { Component } from 'react';
import { Panel, ListGroup, ListGroupItem } from 'react-bootstrap';
import { ButtonContext } from './ButtonContext';

class ButtonPanel extends Component {
  static contextType = ButtonContext;
  render() {
    return (
      <ButtonContext.Consumer>
        {
          ({ showPanel }) => {
            if (showPanel) {
              return (
                <Panel id="tasksPanel">
                  <Panel.Heading >Panel Heading</Panel.Heading>
                  <ListGroup>
                    <ListGroupItem>No Items.</ListGroupItem>
                  </ListGroup>
                </Panel>
              );
            }
            return null;
          }
        }
      </ButtonContext.Consumer>
    );
  }
}

export { ButtonPanel };

我还尝试简单地访问 ButtonPanel 组件中的上下文,如下所示:

render() {
    const context = this.context;
    return context.showPanel ?
      (
        <Panel id="tasksPanel">
          <Panel.Heading >Tasks</Panel.Heading>
          <ListGroup>
            <ListGroupItem className="tasks-empty-state">No tasks available.</ListGroupItem>
          </ListGroup>
        </Panel>
      )
      :
      null;
  }

我做错了什么?

谢谢

最佳答案

来自 React docs :

Accepts a value prop to be passed to consuming components that are descendants of this Provider.

所以这意味着 <ButtonContext.Provider>必须包裹<ButtonContext.Consumer>或者它必须位于组件层次结构的较高位置。

因此,根据您的用例,您可以这样做:

// This app component is the div that wraps both Toolbar and Content. You can name it as you want
class App extends Component {
  state = {
    showPanel: false,
  }

  handleTogglePanel = () => this.setState(prevState => ({ togglePanel: !prevState.togglePanel }));

 render() {
   return (
     <ButtonContext.Provider value={{ showPanel: this.state.showPanel, handleTogglePanel: this.handleTogglePanel }}>
       <Toolbar>
         <Button />
       </Toolbar>
       <Content>
         <ButtonPanel />
       </Content>
     </ButtonContext.Provider>
   );
 }
}

class Button extends Component {
  ...
    <ButtonContext.Consumer>
      {({ handleTogglePanel }) => <a onClick={handleTogglePanel} />}
    </ButtonContext.Consumer>
}

class ButtonPanel extends Component {
  ...
    <ButtonContext.Consumer>
      {({ showPanel }) => showPanel && <Panel>...</Panel>}
    </ButtonContext.Consumer>
}

关于javascript - 使用 Context API 在非嵌套组件之间传递变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57167905/

相关文章:

javascript - 如何设置可以在 react-select 中选择的最大项目数?

javascript - 如何在ReactJS中通过ref动态设置State

javascript - React 上下文返回未定义

javascript - 如何使用 React js 中的上下文将函数从 FUNCTIONAL 传递到 CLASS 组件并在渲染之外访问它(不带 prop )?

javascript - HTML5 输入类型时间——选择或更改了哪一部分(小时或分钟)?

javascript - Edge Animate 自定义百分比预加载器

javascript - 如何在段的 fillStyle 上使用渐变颜色。 [风轮]

javascript - 如何在映射循环中从 onClick 向函数发送唯一值

javascript - 在 native react 中,如何将base64图像转换为jpg然后保存到临时路径?

javascript - 使用 ContextAPI 不会重新呈现其使用者,但内容已更改。为什么?