React/Gatsby 组件交互(提升状态)与 MDX 文件中的组件

我将 Gatsby 与 MDX 插件一起使用。所以我可以在 markdown 中使用 React 组件。没关系。


我有组件,互相交谈。为此,我使用提升状态向上模式。没关系。


这是一个基本的 Counter 示例,用于展示我的概念验证代码。


import React from "react"


export class Counter extends React.Component {

  constructor(props) {

    super(props)

    this.state = { count: 0 }

    this.handleCounterUpdate = this.handleCounterUpdate.bind(this)

  }


  handleCounterUpdate() {

    this.setState({ count: this.state.count + 1 })

  }


  render() {

    const children = React.Children.map(this.props.children, child => {

      const additionalProps = {}

      additionalProps.count = this.state.count

      additionalProps.handleCounterUpdate = this.handleCounterUpdate

      return React.cloneElement(child, additionalProps)

    })

    return <div>{children}</div>

  }

}


export function Display({ count }) {

  return <h2>Current counter is: {count}</h2>

}


export function UpdateButton({ handleCounterUpdate }) {

  return <button onClick={handleCounterUpdate}>Increment couter by one</button>

}

通过此设置,可以使用这样的组件


<Counter>

  <Display />

  <UpdateButton />

</Counter>

甚至像这样


<Counter>

  <Display />

  <UpdateButton />

  <Display />

  <Display />

</Counter>

没关系。


在现实世界中,封闭的 Counter 组件(状态持有者)将类似于 Layout 组件。在<Layout>模板中使用并呈现 MDX 页面。这看起来像这样:


<SiteLayout>

  <SEO title={title} description={description} />

  <TopNavigation />

  <Display />       // The state holder is <SiteLayout>, not <Counter> 

  <Breadcrumb location={location} />

  <MDXRenderer>{page.body}</MDXRenderer>  // The rendered MDX

</SiteLayout>

(<UpdateButton>在现实世界中类似<AddToCartButton>)在 MDX 页面上,不再是<Layout>组件的直接子项。


该模式不再起作用。


我该如何解决这个问题?


繁华开满天机
浏览 104回答 1
1回答

潇潇雨雨

import React from "react"// This is a proof of concept (POC) for intercomponent communication using// React Context//// In the real world Gatsby/React app we use a kind of cart summary component// at top right of each page. The site consists of thousands of pages with detailed// product information and a blog. Users have the possibility to add products directly// from product information pages and blog posts. Posts and pages are written in// MDX (Mardown + React components). All <AddToCartButtons> reside in MDX files.//// This code uses a "increment counter button" (= add to cart button) and a// display (= cart summary) as POC//// More information at// https://reactjs.org/docs/context.html#updating-context-from-a-nested-componentexport const CounterContext = React.createContext()// The <Layout> component handles all business logic. Thats fine. We have// very few app features.export class Layout extends React.Component {&nbsp; constructor(props) {&nbsp; &nbsp; super(props)&nbsp; &nbsp; this.handleCounterUpdate = this.handleCounterUpdate.bind(this)&nbsp; &nbsp; this.state = { count: 0, increment: this.handleCounterUpdate }&nbsp; }&nbsp; handleCounterUpdate() {&nbsp; &nbsp; this.setState({ count: this.state.count + 1 })&nbsp; }&nbsp; render() {&nbsp; &nbsp; return (&nbsp; &nbsp; &nbsp; <div style={{ backgroundColor: "silver", padding: "20px" }}>&nbsp; &nbsp; &nbsp; &nbsp; <CounterContext.Provider value={this.state}>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {this.props.children}&nbsp; &nbsp; &nbsp; &nbsp; </CounterContext.Provider>&nbsp; &nbsp; &nbsp; </div>&nbsp; &nbsp; )&nbsp; }}export class UpdateButton extends React.Component {&nbsp; static contextType = CounterContext&nbsp; render() {&nbsp; &nbsp; const count = this.context.count&nbsp; &nbsp; const increment = this.context.increment&nbsp; &nbsp; return (&nbsp; &nbsp; &nbsp; <button onClick={increment}>&nbsp; &nbsp; &nbsp; &nbsp; Increment counter (current value: {count})&nbsp; &nbsp; &nbsp; </button>&nbsp; &nbsp; )&nbsp; }}export class Display extends React.Component {&nbsp; static contextType = CounterContext&nbsp; render() {&nbsp; &nbsp; return (&nbsp; &nbsp; &nbsp; <div&nbsp; &nbsp; &nbsp; &nbsp; style={{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; backgroundColor: "white",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; padding: "10px",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; margin: "10px 0 0 0"&nbsp; &nbsp; &nbsp; &nbsp; }}&nbsp; &nbsp; &nbsp; >&nbsp; &nbsp; &nbsp; &nbsp; <div>I'm Display. I know the count: {this.context.count}</div>&nbsp; &nbsp; &nbsp; &nbsp; <div>{this.props.children}</div>&nbsp; &nbsp; &nbsp; </div>&nbsp; &nbsp; )&nbsp; }}// Function components use <CounterContext.Consumer>. Class components// use static contextType = CounterContextexport function AChild() {&nbsp; return (&nbsp; &nbsp; <CounterContext.Consumer>&nbsp; &nbsp; &nbsp; {context => (&nbsp; &nbsp; &nbsp; &nbsp; <span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; I'm a child of Display. I know the count too: {context.count}&nbsp; &nbsp; &nbsp; &nbsp; </span>&nbsp; &nbsp; &nbsp; )}&nbsp; &nbsp; </CounterContext.Consumer>&nbsp; )}像这样使用<Layout>&nbsp; <Display>&nbsp; &nbsp; <AChild />&nbsp; </Display>&nbsp; // UpdateButton inside MDX files&nbsp; <MDXRenderer>{page.body}</MDXRenderer>&nbsp;// Or elsewhere&nbsp; <UpdateButton />&nbsp;</Layout>
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript