Как правильно использовать типы TypeScript с холстом стилизованного компонента в React

Я создаю компонент React в Gatsby, используя TypeScript, и определил стилизованный компонент холста следующим образом:

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?


person reymon359    schedule 31.05.2020    source источник
comment
Это может быть отчасти связано.   -  person Ajeet Shah    schedule 01.06.2020
comment
Спасибо @AjeetShah, я посмотрю!   -  person reymon359    schedule 01.06.2020


Ответы (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>
  );

person reymon359    schedule 01.06.2020
comment
Проверьте мой обновленный ответ. Я забыл установить тип canvasRef в общем useRef. Теперь он должен работать. Конечно, ваше решение работает, но вы будете вынуждены выполнять много повторных рендеров. Просто попробуйте console.log('hi') в теле Component, чтобы понять, что я имею в виду. - person 101arrowz; 01.06.2020
comment
Кроме того, единственной проблемой с моим исходным кодом была жалоба TypeScript, но в любом случае проблем во время выполнения быть не должно. - person 101arrowz; 01.06.2020

Background - это React.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 действительно полезен, только если вы что-то сделаете с реквизитами .

person 101arrowz    schedule 31.05.2020
comment
Привет, @ 101arrowz Спасибо за ответ, он заставил меня понять некоторые непонятные мне вещи. Я пробовал ваш код, но получил ошибку при использовании контекста о том, что он нулевой. Но мне понравился ваш подход к добавлению стиля в строку. Мне нравится использовать стилизованные компоненты, потому что я не только использую реквизиты, но и переименовываю мои компоненты в более значимые имена, которые сделают код, в конце концов, более разборчивым. Ваш подход помог мне найти решение, которое решило проблему нуля в контексте. - person reymon359; 01.06.2020