兄弟组件之间的 React Konva 共享引用抛出错误
React Konva share ref between sibling components throws error
我有 App.tsx
,其中包含 2 个同级组件:
Konva.tsx
:它具有 Canvas
Options.tsx
:它有一个下载Canvas按钮
所以我在 App.tsx
中创建了一个名为 stageRef
的 ref
以将其传递给 Konva.tsx
& Options.tsx
。我使用 React.forwardRef
将引用转发给子组件。
App.tsx
import * as React from 'react'
import type { Stage as StageType } from 'konva/types/Stage'
import { Konva, Options } from '@/components/index'
import { FrameItProvider } from '@/store/index'
const App = () => {
const stageRef = React.createRef<StageType>()
return (
<>
<Konva ref={stageRef} />
<Options ref={stageRef} />
</>
)
}
export default App
在Konva.tsx
中,ref
指向Canvas,因此它可以访问DOM中的元素。
Konva.tsx
import * as React from 'react'
import { observer } from 'mobx-react'
import { useFrameItStore } from '@/store/index'
import { BrowserWindow } from '@/components/index'
import type { Window } from '@/types/index'
import type { Stage as StageType } from 'konva/types/Stage'
interface IProps {
className?: string
}
export const Konva = observer(
React.forwardRef<StageType, IProps>(({ className }: IProps, forwardedRef) => {
const frameItStore = useFrameItStore()
const browser: Window = frameItStore.browser
return (
<>
<Stage
width={browser.width}
height={browser.height}
ref={forwardedRef}
className={className}
>
<Layer>
<BrowserWindow />
</Layer>
</Stage>
</>
)
})
)
在 Options.tsx
中,我使用 downloadImage
和 forwardedRef
触发下载调用。
Options.tsx
import * as React from 'react'
import { observer } from 'mobx-react'
import type { Stage as StageType } from 'konva/types/Stage'
import { useFrameItStore } from '@/store/index'
import type { TrafficSignalStyle } from '@/types/index'
interface IProps {
className?: string
}
export const Options = observer(
React.forwardRef<StageType, IProps>((props: IProps, forwardedRef) => {
const frameItStore = useFrameItStore()
const downloadImage: (stageRef: React.ForwardedRef<StageType>) => void =
frameItStore.downloadImage
return (
<div>
<button onClick={() => downloadImage(forwardedRef)}>
Download Canvas
</button>
</div>
)
})
)
我正在使用 MobX 来管理我的商店。但是,forwardRef
会导致问题。
store/index.ts
import type { Stage as StageType } from 'konva/types/Stage'
import type { IFrameItStore } from '@/types/index'
export class FrameItStore implements IFrameItStore {
downloadImage(stageRef: React.ForwardedRef<StageType>) {
console.log(stageRef)
stageRef
.current!.getStage()
.toDataURL({ mimeType: 'image/jpeg', quality: 1 })
}
}
types/index.ts
export interface IFrameItStore {
downloadImage(stageRef: React.ForwardedRef<StageType>): void
}
我在 store/index.ts
中遇到 2 个 TypeScript 错误:
TS2531: Object is possibly 'null'.
在 stageRef
当我尝试访问 stageRef.current
和
TS2339: Property 'current' does not exist on type '((instance: Stage | null) => void) | MutableRefObject<Stage | null>'.
属性 'current' 不存在于类型 '(instance: Stage | null) => void' 上。
于 current
我试过不使用 ForwardedRef
但它给出了类型不匹配的错误所以我必须使用 ForwardedRef
但我不确定如何解决这个问题?
我在 App.tsx
中创建了一个 ref
,然后将其传递给了 Konva.tsx
。我使用 React.forwardRef
函数捕获了 ref。
然后我使用 Konva.tsx
中鲜为人知的 useImperativeHandle
钩子来访问 App.tsx
中的函数 downloadImage
然后将函数 downloadImage
直接传递给Options.tsx
.
我没有在 MobX 商店中保留任何东西。只是将它保存在本地的 Konva
组件中,以便于访问。旧规则是,如果它不打算在任何其他组件中使用,那么它应该尽可能靠近组件。
App.tsx
import * as React from 'react'
import { Konva, Options } from '@/components/index'
const App = () => {
const stageRef = React.useRef<{ downloadImage: Function }>(null)
return (
<>
<Konva ref={stageRef} />
<Options downloadImage={() => stageRef?.current?.downloadImage()} />
</>
)
}
export default App
Konva.tsx
import * as React from 'react'
import { observer } from 'mobx-react'
import { useFrameItStore } from '@/store/index'
import { BrowserWindow } from '@/components/index'
import type { Window } from '@/types/index'
import type { Stage as StageType } from 'konva/types/Stage'
interface IProps {
className?: string
}
interface ForwardedRef {
downloadImage: Function
}
export const Konva = observer(
React.forwardRef<ForwardedRef, IProps>(
({ className }: IProps, forwardedRef) => {
const frameItStore = useFrameItStore()
const browser: Window = frameItStore.browser
const stageRef = React.useRef<StageType>(null)
React.useImperativeHandle(
forwardedRef,
() => ({
downloadImage: () =>
stageRef.current
?.getStage()
.toDataURL({ mimeType: 'image/jpeg', quality: 1 }),
}),
[]
)
return (
<Stage
width={browser.width}
height={browser.height}
ref={stageRef}
className={className}
>
<Layer>
<BrowserWindow />
</Layer>
</Stage>
)
}
)
)
Options.tsx
import * as React from 'react'
import { observer } from 'mobx-react'
interface IProps {
className?: string
downloadImage: Function
}
export const Options = observer((props: IProps) => {
const { downloadImage } = props
return (
<div>
<button onClick={() => console.log(downloadImage())}>
Download Image
</button>
</div>
)
})
这是 CodeSandBox 上的完整工作演示 → https://codesandbox.io/s/react-konva-share-refs-between-siblings-dsd97?file=/src/App.tsx
我有 App.tsx
,其中包含 2 个同级组件:
Konva.tsx
:它具有 CanvasOptions.tsx
:它有一个下载Canvas按钮
所以我在 App.tsx
中创建了一个名为 stageRef
的 ref
以将其传递给 Konva.tsx
& Options.tsx
。我使用 React.forwardRef
将引用转发给子组件。
App.tsx
import * as React from 'react'
import type { Stage as StageType } from 'konva/types/Stage'
import { Konva, Options } from '@/components/index'
import { FrameItProvider } from '@/store/index'
const App = () => {
const stageRef = React.createRef<StageType>()
return (
<>
<Konva ref={stageRef} />
<Options ref={stageRef} />
</>
)
}
export default App
在Konva.tsx
中,ref
指向Canvas,因此它可以访问DOM中的元素。
Konva.tsx
import * as React from 'react'
import { observer } from 'mobx-react'
import { useFrameItStore } from '@/store/index'
import { BrowserWindow } from '@/components/index'
import type { Window } from '@/types/index'
import type { Stage as StageType } from 'konva/types/Stage'
interface IProps {
className?: string
}
export const Konva = observer(
React.forwardRef<StageType, IProps>(({ className }: IProps, forwardedRef) => {
const frameItStore = useFrameItStore()
const browser: Window = frameItStore.browser
return (
<>
<Stage
width={browser.width}
height={browser.height}
ref={forwardedRef}
className={className}
>
<Layer>
<BrowserWindow />
</Layer>
</Stage>
</>
)
})
)
在 Options.tsx
中,我使用 downloadImage
和 forwardedRef
触发下载调用。
Options.tsx
import * as React from 'react'
import { observer } from 'mobx-react'
import type { Stage as StageType } from 'konva/types/Stage'
import { useFrameItStore } from '@/store/index'
import type { TrafficSignalStyle } from '@/types/index'
interface IProps {
className?: string
}
export const Options = observer(
React.forwardRef<StageType, IProps>((props: IProps, forwardedRef) => {
const frameItStore = useFrameItStore()
const downloadImage: (stageRef: React.ForwardedRef<StageType>) => void =
frameItStore.downloadImage
return (
<div>
<button onClick={() => downloadImage(forwardedRef)}>
Download Canvas
</button>
</div>
)
})
)
我正在使用 MobX 来管理我的商店。但是,forwardRef
会导致问题。
store/index.ts
import type { Stage as StageType } from 'konva/types/Stage'
import type { IFrameItStore } from '@/types/index'
export class FrameItStore implements IFrameItStore {
downloadImage(stageRef: React.ForwardedRef<StageType>) {
console.log(stageRef)
stageRef
.current!.getStage()
.toDataURL({ mimeType: 'image/jpeg', quality: 1 })
}
}
types/index.ts
export interface IFrameItStore {
downloadImage(stageRef: React.ForwardedRef<StageType>): void
}
我在 store/index.ts
中遇到 2 个 TypeScript 错误:
TS2531: Object is possibly 'null'.
在 stageRef
当我尝试访问 stageRef.current
和
TS2339: Property 'current' does not exist on type '((instance: Stage | null) => void) | MutableRefObject<Stage | null>'.
属性 'current' 不存在于类型 '(instance: Stage | null) => void' 上。
于 current
我试过不使用 ForwardedRef
但它给出了类型不匹配的错误所以我必须使用 ForwardedRef
但我不确定如何解决这个问题?
我在 App.tsx
中创建了一个 ref
,然后将其传递给了 Konva.tsx
。我使用 React.forwardRef
函数捕获了 ref。
然后我使用 Konva.tsx
中鲜为人知的 useImperativeHandle
钩子来访问 App.tsx
中的函数 downloadImage
然后将函数 downloadImage
直接传递给Options.tsx
.
我没有在 MobX 商店中保留任何东西。只是将它保存在本地的 Konva
组件中,以便于访问。旧规则是,如果它不打算在任何其他组件中使用,那么它应该尽可能靠近组件。
App.tsx
import * as React from 'react'
import { Konva, Options } from '@/components/index'
const App = () => {
const stageRef = React.useRef<{ downloadImage: Function }>(null)
return (
<>
<Konva ref={stageRef} />
<Options downloadImage={() => stageRef?.current?.downloadImage()} />
</>
)
}
export default App
Konva.tsx
import * as React from 'react'
import { observer } from 'mobx-react'
import { useFrameItStore } from '@/store/index'
import { BrowserWindow } from '@/components/index'
import type { Window } from '@/types/index'
import type { Stage as StageType } from 'konva/types/Stage'
interface IProps {
className?: string
}
interface ForwardedRef {
downloadImage: Function
}
export const Konva = observer(
React.forwardRef<ForwardedRef, IProps>(
({ className }: IProps, forwardedRef) => {
const frameItStore = useFrameItStore()
const browser: Window = frameItStore.browser
const stageRef = React.useRef<StageType>(null)
React.useImperativeHandle(
forwardedRef,
() => ({
downloadImage: () =>
stageRef.current
?.getStage()
.toDataURL({ mimeType: 'image/jpeg', quality: 1 }),
}),
[]
)
return (
<Stage
width={browser.width}
height={browser.height}
ref={stageRef}
className={className}
>
<Layer>
<BrowserWindow />
</Layer>
</Stage>
)
}
)
)
Options.tsx
import * as React from 'react'
import { observer } from 'mobx-react'
interface IProps {
className?: string
downloadImage: Function
}
export const Options = observer((props: IProps) => {
const { downloadImage } = props
return (
<div>
<button onClick={() => console.log(downloadImage())}>
Download Image
</button>
</div>
)
})
这是 CodeSandBox 上的完整工作演示 → https://codesandbox.io/s/react-konva-share-refs-between-siblings-dsd97?file=/src/App.tsx