[英]React/Gatsby component interaction (lifting state up) with components in MDX files
I use Gatsby with the MDX plugin.我将 Gatsby 与 MDX 插件一起使用。 So I can use React components in markdown.
所以我可以在 markdown 中使用 React 组件。 That's fine.
没关系。
I have components, talking to each other.我有组件,互相交谈。 To do this I use the Lifting State Up Pattern .
为此,我使用Lifting State Up Pattern 。 That's fine.
没关系。
Here is a basic Counter example, to show my proof of concept code.这是一个基本的 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>
}
With this setup, one can use the components like this通过此设置,可以使用这样的组件
<Counter>
<Display />
<UpdateButton />
</Counter>
or even like this甚至像这样
<Counter>
<Display />
<UpdateButton />
<Display />
<Display />
</Counter>
That's fine.没关系。
In real-world, the enclosing Counter component (state holder), will be something like a Layout component.在现实世界中,封闭的 Counter 组件(状态持有者)将类似于 Layout 组件。 The
<Layout>
is used in a template and renders the MDX pages. <Layout>
在模板中使用并呈现 MDX 页面。 This looks like that:这看起来像这样:
<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>
The <UpdateButton>
(in real-world something like <AddToCartButton>
) is on the MDX page and not anymore a direct child from the <Layout>
component. <UpdateButton>
(在现实世界中类似于<AddToCartButton>
)位于 MDX 页面上,不再是<Layout>
组件的直接子级。
The pattern does not work anymore.该模式不再起作用。
How can I resolve this?我该如何解决这个问题?
Thanks all谢谢大家
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>
)
}
Use it like this像这样使用它
<Layout>
<Display>
<AChild />
</Display>
// UpdateButton inside MDX files
<MDXRenderer>{page.body}</MDXRenderer>
// Or elsewhere
<UpdateButton />
</Layout>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.