首页 > 解决方案 > React - 使用 Context API 通过另一个组件更改多个单独的组件

问题描述

假设我有三个组件AppBlockBlockOptions

App有一个名为的数组blocks,它包含所有块组件。这些块在某种画板内渲染。因为每个块都可以修改,所以我想在选择BlockOptionsa 时充当属性面板Block。那Block应该可以从那里修改。请记住,这BlockOptions是在一个完全不同的位置。

应用程序.js:

class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
      artboardSize: {
        width: 300,
        height: 200
      },
      blocks: []
    }
  }
  // App component contains several methods that change the blocks array, like this one
  addBlock(width, height) {
    const newBlock = {
      width: width,
      height: height
    }

    this.setState(prevState => ({
      blocks: [...prevState.blocks, newBlock]
    }));
  }
  render() {
    return (
      <GlobalContext.Provider value={this}>
        <div className="app">
          <Artboard /> // Where all Blocks go
          <Sidebar /> // Where BlockInfo goes
        </div>
      </GlobalContext.Provider>
    )
  }
}

如上所示,我使用 Context API 让所有组件都可以访问App's 的状态和方法。因此,例如,如果单击页面上某处的按钮,该组件将调用App'saddBlock()方法来创建一个新块。

这就是我当前渲染每个块的方式Artboard

{context.state.blocks.map((block, key) => (
  <Block key={key} width={block.width * context.scale} height={block.height * context.scale} />
))}

在 Block.js 中,我想在用户单击一个块时将App's blocks 数组更改selected为:true

class Block extends Component {
  constructor(props) {
    super(props);

    this.state = {
      width: this.props.width,
      height: this.props.height,
      selected: false
      // etc...
    }
  }
  handleOnClick() {
    this.setState({
      selected: true
    });

    // But how do I update this in App?
  }
  render() {
    return (
      <div className="block" onClick={() => this.handleOnClick()}></div>
    )
  }
}

但我不能。我可以更新 中的状态 Block但不能更新整个应用程序本身。我该怎么做?

我对 React 很陌生。所以也许使用 Context API 不合适,我真的不知道。也许我的整个思维方式都搞砸了。也许有更好的方法来解决这个问题?

基本上我想要做的是: 拥有一组彼此不同的组件,以便能够从某种“选项面板”中进行更改。每个块都是不同的,所以这个面板应该根据所选块的状态而变化。

标签: javascriptreactjsreact-context

解决方案


无论您决定使用上下文、reducer 还是状态,您都需要将一个函数传递给您的块组件,该函数将被顶级组件调用以更新传递给子组件的值。

如果要使用上下文,可以将值更改为:

<GlobalContext.Provider value={{ blocks: this.state.blocks, addBlock: this.addBlock }} >

这样,上下文的任何消费者不仅可以访问这些块,而且还可以调用一个函数来为应用程序中的任何其他消费者更新它们。

{context.blocks.map((block, key) => <Block ... onAdd={context.addBlock} />)}

在块内:

handleOnClick() {
  this.setState ...
  this.props.onAdd();
}

推荐阅读