如何在 React 上正确使用带有样式组件画布的 TypeScript 类型

Posted

技术标签:

【中文标题】如何在 React 上正确使用带有样式组件画布的 TypeScript 类型【英文标题】:How to properly use TypeScript types with a Styled Component canvas on React 【发布时间】:2020-09-19 03:41:13 【问题描述】:

我正在使用 TypeScript 在 Gatsby 上创建一个 React 组件,并以这种方式定义了一个画布样式组件:

const Background = styled.canvas`
  position: fixed;
  width: 100%;
  height: 100%;
`;

为了使用它,我以这种方式为其分配类型:

const canvas: htmlCanvasElement = Background,
  context = Background.getContext('2d');

但我在画布类型中遇到此错误:

Type 'String & StyledComponentBase<"canvas", any, , never> & NonReactStatics<never, >' is missing the following properties from type 'HTMLCanvasElement': height, width, getContext, toBlob, and 238 more.

.getContext() 方法也出现错误:

This expression is not callable.
Type 'never' has no call signatures.

我一直在寻找解决方案,但找不到适合此特定问题的解决方案。 有人可以向我解释一下在 TypeScript 中使用 Styled Component 画布的最佳方式吗?

【问题讨论】:

This 可能有点相关。 谢谢@AjeetShah,我去看看! 【参考方案1】:

BackgroundReact.Component(即创建虚拟元素的函数)而不是 HTMLCanvasElement。不仅需要调用该函数,它甚至可以远程返回任何东西,例如HTMLCanvasElement,而且您还需要访问底层 DOM 元素才能使其工作。不过,我确实有一个建议,您可以尝试一下。

import  useRef, useEffect  from 'react';

const Background = styled.canvas`
  position: fixed;
  width: 100%;
  height: 100%;
`;

const ComponentUsingTheCanvas = () => 
  const canvasRef = useRef<HTMLCanvasElement>(null);
  useEffect(() => 
    const context = canvasRef.current.getContext('2d');
    // Do stuff with your canvas context here
  );
  return (
    <Background ref=canvasRef />
  );

请注意,我没有输入任何内容,因为 TypeScript 大部分时间都可以自动完成。

顺便说一句,既然可以内联样式,为什么还要使用样式化组件呢? styled-components 只有在你 do something with the props 时才真正有用。

【讨论】:

嗨,@101arrowz 谢谢你的回答,这让我明白了一些我不清楚的事情。我尝试了您的代码,但在使用有关它为空的上下文时出现错误。但我喜欢你添加内联样式的方法。我喜欢使用 styled-components,因为不仅使用道具,而且将我的组件重命名为更有意义的名称,最终使代码更清晰。您的方法帮助我找到了解决上下文中 null 问题的解决方案。【参考方案2】:

@101arrowz 的答案几乎是正确的,但上下文有问题导致我出现此错误。

Object is possibly 'null'.

但它帮助我找到了一种内联样式的不同方法并以这种方式解决问题:

const Component: React.FC = () => 
  const canvasRef = React.useRef<HTMLCanvasElement>(null);
  const [context, setContext] = React.useState<CanvasRenderingContext2D | null>(
    null
  );

  React.useEffect(() => 
    if (canvasRef.current) 
      const renderCtx = canvasRef.current.getContext('2d');

      if (renderCtx) 
        setContext(renderCtx);
      
    
  , [context]);

  return (
    <div>
      <canvas
        id="canvas"
        ref=canvasRef
        style=
          position: 'fixed',
          width: '100%',
          height: '100%'
        
      ></canvas>
    </div>
  );

【讨论】:

检查我更新的答案。我忘了在useRef 泛型中设置canvasRef 的类型。它现在应该可以工作了。当然,您的解决方案有效,但您将强制进行许多重新渲染。只需在 Component 的正文中尝试 console.log('hi') 即可了解我的意思。 另外,我的原始代码的唯一问题是 TypeScript 抱怨,但无论哪种方式在运行时都应该没有问题。

以上是关于如何在 React 上正确使用带有样式组件画布的 TypeScript 类型的主要内容,如果未能解决你的问题,请参考以下文章

使用带有样式组件和主题的 react-test-renderer (React Native)

如何在带有 TypeScript 的 React-Native 中使用 styled-component 键入无状态功能组件?

在 React 样式组件上使用 'ref' 不起作用

如何根据多个条件设置 React 组件的样式?

如何正确使用带有 React 功能组件的键?这是我的喜欢按钮:

如何在 Typescript 中正确使用 React.lazy() 来导入带有泛型类型参数的反应组件?