How to use variable declared in useEffect() in another function?

Irakli Tchigladze picture Irakli Tchigladze · Sep 27, 2019 · Viewed 7.5k times · Source

p.s solved the problem i was having, but i would still like to hear your thoughts on this and my code, if you have time :)

I can only assign a value to that variable ONLY after render has been completed, so i assume i must declare that variable in useEffect(), and it is impossible to assign value to it in global scope(which is executed before anything renders). But i also want to use that variable in another useEffect(), but i can't, since it's declared inside a function and it does not belong to global scope. Also, is it normal to have two useEffect -s? One i need for grabbing a context of canvas, and keeping that context consistent (not grabbing new one on every DOM update, as it happens when i don't put [] as second argument of first useEffect). And the other is for doing things with that unique context as state changes. Does it make sense? My code:

import React, { useState, useRef, useEffect } from "react";
import { degreesToRadiansFlipped } from "./helpers/degreesToRadiansFlipped";
function Circle() {
  let [degree, setDegree] = useState(0);
  const canvas = useRef();
  const inputField = useRef();
  const coordinateX = Math.cos(degreesToRadiansFlipped(degree)) * 100 + 250;
  const coordinateY = Math.sin(degreesToRadiansFlipped(degree)) * 100 + 250;

  useEffect(() => {
    const context = canvas.current.getContext("2d");
    drawCircle(context, coordinateX, coordinateY);
    return context;
    /*return function cleanUp() {
      context.clearRect(0, 0, 500, 500);
      context.beginPath();
      drawCircle(context, coordinateX, coordinateY);
    };*/
  }, []);
  useEffect(() => {
    drawCircle(context, coordinateX, coordinateY);
  }, [degree]);
  let drawCircle = function(context, x, y) {
    context.beginPath();
    //arc has option to make it anti-clockwise, making flipping radians redundant
    context.arc(250, 250, 100, 0, Math.PI * 2);
    context.moveTo(250, 250);
    context.lineTo(x, y);
    context.stroke();
  };

  return (
    <div>
      <canvas ref={canvas} width={500} height={500}></canvas>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          setDegree(inputField.current.value);
        }}
      >
        <input type="text" ref={inputField}></input>
        <button type="submit">Submit</button>
      </form>
    </div>
  );
}

export default Circle;

Answer

Ariel Batista picture Ariel Batista · Sep 27, 2019

yes it makes sense to have multiples useEffect, when they have different arguments in the second parameter as you did.

you can declare the variable outside the useEffec as undefined.

let context = undefined // is not constant
  useEffect(() => {
    context = canvas.current.getContext("2d");
    drawCircle(context, coordinateX, coordinateY);
    return context;
    /*return function cleanUp() {
      context.clearRect(0, 0, 500, 500);
      context.beginPath();
      drawCircle(context, coordinateX, coordinateY);
    };*/
  }, []);
  useEffect(() => {
    drawCircle(context, coordinateX, coordinateY);
  }, [degree]);

this way is available in the function scope