为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

繁华开满天机 2022-12-18 18:58:50
我将 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>组件的直接子项。该模式不再起作用。我该如何解决这个问题?
查看完整描述

1 回答

?
潇潇雨雨

TA贡献1833条经验 获得超4个赞

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-component


export 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 {

  constructor(props) {

    super(props)

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

    this.state = { count: 0, increment: this.handleCounterUpdate }

  }


  handleCounterUpdate() {

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

  }

  render() {

    return (

      <div style={{ backgroundColor: "silver", padding: "20px" }}>

        <CounterContext.Provider value={this.state}>

          {this.props.children}

        </CounterContext.Provider>

      </div>

    )

  }

}


export class UpdateButton extends React.Component {

  static contextType = CounterContext

  render() {

    const count = this.context.count

    const increment = this.context.increment

    return (

      <button onClick={increment}>

        Increment counter (current value: {count})

      </button>

    )

  }

}


export class Display extends React.Component {

  static contextType = CounterContext


  render() {

    return (

      <div

        style={{

          backgroundColor: "white",

          padding: "10px",

          margin: "10px 0 0 0"

        }}

      >

        <div>I'm Display. I know the count: {this.context.count}</div>

        <div>{this.props.children}</div>

      </div>

    )

  }

}


// Function components use <CounterContext.Consumer>. Class components

// use static contextType = CounterContext

export function AChild() {

  return (

    <CounterContext.Consumer>

      {context => (

        <span>

          I'm a child of Display. I know the count too: {context.count}

        </span>

      )}

    </CounterContext.Consumer>

  )

}

像这样使用


<Layout>

  <Display>

    <AChild />

  </Display>

  // UpdateButton inside MDX files

  <MDXRenderer>{page.body}</MDXRenderer>

 // Or elsewhere

  <UpdateButton /> 

</Layout>


查看完整回答
反对 回复 2022-12-18
  • 1 回答
  • 0 关注
  • 103 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信