Uncaught TypeError: невозможно прочитать свойство getContext, равное null, в реакции рендеринга - PullRequest
0 голосов
/ 02 августа 2020

Я пытаюсь реализовать веб-сокеты в своем интерфейсе реагирования, чтобы передать ему несколько кадров с помощью холста.

Сначала код работал нормально, и я мог очень хорошо получать данные ... но когда я необходимо добавить вызов функции из родительского компонента, я получил сообщение об ошибке:

videoSocket. js: 51 Uncaught TypeError: невозможно прочитать свойство getContext из null

Это код:

import React, { Component } from "react";
import "./canvas.css";

function b64toBlob(dataURI) {
  var byteString = atob(dataURI.split(",")[0]);

  var ab = new ArrayBuffer(byteString.length);
  var ia = new Uint8Array(ab);

  for (var i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i);
  }
  return new Blob([ab], { type: "image/jpeg" });
} /*
    ws.onmessage = function(event) {
        
        var img=document.getElementById("video_frames");
        var urlObject = URL.createObjectURL(event.data);
        img.src = urlObject;
        document.body.appendChild(img);
    }*/

class VideoSocket extends Component {
  state = {
    websocket: null,
  };
  constructor(props) {
    super(props);
    var ws = new WebSocket("ws://" + props.link);
    this.state = {
      websocket: ws,
    };
  }

  render() {
    const self = this;
    this.state.websocket.onmessage = function (event) {
      var js = JSON.parse(atob(event.data.split(",")[0]));

      var data = b64toBlob(js["data"]);
      var personinfo = { infos: js["infos"] };
      console.log(self.props);
      self.props.setdata(personinfo);

      var urlObject = URL.createObjectURL(data);

      var canvas = document.getElementById("tools_sketch");
      /*
    canvas.width = window.innerWidth; // equals window dimension
    canvas.height = window.innerHeight;*/
      var ctx = canvas.getContext("2d");

      var image = new Image();
      image.onload = function () {
        ctx.drawImage(
          image,
          0,
          0,
          image.width,
          image.height, // source rectangle
          0,
          0,
          canvas.width,
          canvas.height
        );
      };

      image.src = urlObject;
    };
    return (
      <div>
        <canvas
          id="tools_sketch"
          width={this.props.width}
          height={this.props.height}
        >
          Sorry, your browser doesn't support the &lt;canvas&gt; element.
        </canvas>
      </div>
    );
  }
}

export default VideoSocket;

Когда я удаляю

self.props.setdata(personinfo);

, он работает нормально, но когда я добавляю его, независимо от того, что я пробовал, он не работает.

Я пытался добавить функцию onmessage к componentdidmount, как показано ниже, но получаю ту же ошибку.

import React, { Component } from "react";
import "./canvas.css";

function b64toBlob(dataURI) {
  var byteString = atob(dataURI.split(",")[0]);

  var ab = new ArrayBuffer(byteString.length);
  var ia = new Uint8Array(ab);

  for (var i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i);
  }
  return new Blob([ab], { type: "image/jpeg" });
} /*
    ws.onmessage = function(event) {
        
        var img=document.getElementById("video_frames");
        var urlObject = URL.createObjectURL(event.data);
        img.src = urlObject;
        document.body.appendChild(img);
    }*/

class VideoSocket extends Component {
  state = {
    websocket: null,
  };
  constructor(props) {
    super(props);
    var ws = new WebSocket("ws://" + props.link);
    this.state = {
      websocket: ws,
    };
  }
  componentDidMount() {
    const self = this;
    this.state.websocket.onmessage = function (event) {
      var js = JSON.parse(atob(event.data.split(",")[0]));

      var data = b64toBlob(js["data"]);
      var personinfo = { infos: js["infos"] };
      console.log(self.props);
      self.props.setdata(personinfo);

      var urlObject = URL.createObjectURL(data);

      var canvas = document.getElementById("tools_sketch");
      /*
    canvas.width = window.innerWidth; // equals window dimension
    canvas.height = window.innerHeight;*/
      var ctx = canvas.getContext("2d");

      var image = new Image();
      image.onload = function () {
        ctx.drawImage(
          image,
          0,
          0,
          image.width,
          image.height, // source rectangle
          0,
          0,
          canvas.width,
          canvas.height
        );
      };

      image.src = urlObject;
    };
  }

  render() {
    return (
      <div>
        <canvas
          id="tools_sketch"
          width={this.props.width}
          height={this.props.height}
        >
          Sorry, your browser doesn't support the &lt;canvas&gt; element.
        </canvas>
      </div>
    );
  }
}

export default VideoSocket;

Это код на стороне сервера в python:

#!/usr/bin/env python
import random
import websockets
import asyncio
import os
import numpy as np
import cv2
import json 
import base64


#!/usr/bin/env python

# WS server that sends messages at random intervals


class VideoCamera(object):
    def __init__(self):
        self.video = cv2.VideoCapture('video2.mp4')

    def __del__(self):
        self.video.release()

    def get_frame(self):
        while True:
            ret, image = self.video.read()
            ret, jpeg = cv2.imencode('.jpg', image)
            base6 = base64.b64encode(jpeg.tobytes())
            yield base6.decode('utf-8')


def gen(camera):


    while True:
        image = next(camera.get_frame())

        yield(image)


async def time(websocket, path):
    camera = VideoCamera()
    i = 0
    while True:
        i = i+1
        data = next(gen(camera))
        js = {'data': data, "infos": [
            {'id': 1, 'name': 'name1'}, {'id': 2, 'name': 'name2'}]}

        res_bytes = json.dumps(js).encode('utf-8')
        base6 = base64.b64encode(res_bytes)
        message = base6.decode('utf-8')

        await websocket.send(message)


start_server = websockets.serve(time, "127.0.0.1", 5678)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

Edit : код родительского компонента:

import React, { Component, useState } from "react";

import "antd/dist/antd.css";

import VideoSocket from "../components/videoSocket";
import MyTable from "../components/table";
class Home extends Component {
  state = { personinfo: {} };
  constructor(props) {
    super(props);
    let links = {
      1: "127.0.0.1:5678",
      2: "127.0.0.1:5679",
      3: "127.0.0.1:5680",
      4: "127.0.0.1:5681",
    };
    const CameraId = props.match.params.cameraId;
    console.log(CameraId);
    let link = links[CameraId];
    if (link == null) {
      link = "127.0.0.1:5678";
    }
    let curent = link;
    this.state = {
      links: links,
      curent: curent,
    };
    console.log(link);
  }
  setData = (personinfo) => {
    this.setState({
      personinfo: personinfo,
    });
  };
  render() {
    return (
      <div className=".container-fluid overflow-auto" width="100%">
        <div></div>
        <VideoSocket
          className=""
          width={(window.innerWidth * 75) / 100}
          height="400px"
          link={this.state.curent}
          setdata={this.setData}
          key="1"
        ></VideoSocket>
        <MyTable personinfo={this.state.personinfo}></MyTable>
      </div>
    );
  }
}

export default Home;

Edit : я пытался добавить

shouldComponentUpdate() {
    return false;
  }

к компоненту videosocket, но он все еще сделайте ту же задачу

...