0

Sorry I'm new to React, and so I faced a problem where I have my Context which provides the Time to other components. When I use it only with the component where I display my clock everything is fine. The problem occurs in another component, where I want to display message depending on the time of the day. Too many re-renders. React limits the number of renders to prevent an infinite loop.

My Context Component

import React, { createContext, useState, useEffect } from "react";
import moment from "moment";

export const GreetingContext = createContext();

const getTime = () => {
  return moment();
};

const GreetingContextProvider = (props) => {
  const [currentTime, setCurrentTime] = useState(getTime);


  const setTime = () => {
    setInterval(() => {
      setCurrentTime(getTime);
    }, 1000);

    return () => {
      clearInterval(setTime);
    };
  };
  useEffect(setTime, []);

  return (
    <GreetingContext.Provider value={currentTime}>
      {props.children}
    </GreetingContext.Provider>
  );
};

export default GreetingContextProvider;

And my Message Component

import React, { useState, useContext} from "react";
import { useLocalStorage } from "../custome_hooks/useLocalStorage";
import { GreetingContext } from "../contexts/GreetingContext";

const Greeting = () => {
  const time = useContext(GreetingContext);
  const timeInHours = time.hours();
  const [greeting, setGreeting] = useState("ooo");
  const [name, setName] = useLocalStorage("name", "Your name");


// Setting the greeting depending on the time of the day
  switch (true) {
    case timeInHours > 0 && timeInHours < 5:
        setGreeting("Good night");
      break;
    case timeInHours > 5 && timeInHours < 12:
        setGreeting("Good morning");
      break;
    case timeInHours > 12 && timeInHours < 17:
        setGreeting("Good day");
      break;
      case timeInHours > 17 && timeInHours < 24:
        setGreeting("Good evening");
      break;
    default:
        setGreeting("");
  }



  // Getting the name of the user
  let handleChange = (e) => {
    setName(e.target.value);
  };

  return (
    <div className="greeting_container">
      <h4>{greeting}</h4>
      <input
        type="text"
        size={name.length + 1}
        value={name}
        onChange={handleChange}
      />
    </div>
  );
};

export default Greeting;

Thanks

2 Answers2

1

Ok, I resolved the issue by passing my Switch() into the useEffect hook with second parameter, that I've added to the Message Component.

useEffect(() => {
    switch (true) {
      case timeInHours > 0 && timeInHours < 5:
        setGreeting("Good night");
        break;
      case timeInHours > 5 && timeInHours < 12:
        setGreeting("Good morning");
        break;
      case timeInHours > 12 && timeInHours < 17:
        setGreeting("Good day");
        break;
      case timeInHours > 17 && timeInHours < 24:
        setGreeting("Good evening");
        break;
      default:
        setGreeting("");
    }
  }, [timeInHours]);

So that the Component won't update every second and only in cases when the timeInHours variable is changed.

0

I think your problem is the useEffect where you start your setInterval

It should be:

useEffect(() => {
    setTime()
}, []);

Also when you're updating the time you should call the function.

setCurrentTime(getTime()); // <-- add () to getTime
// same for useState
useState(getTime());

EDIT:

I know this answers your question in another way, but still, I made you a hook insted of context:

import { useState, useEffect } from 'react';
import moment from 'moment';

const getTime = () => moment();

export default () => {
    const [currentTime, setCurrentTime] = useState(getTime());

    const setTime = setInterval(() => {
            setCurrentTime(getTime());
        }, 1000);

    useEffect(() => {
        return () => clearInterval(setTime);
    }, [])

    return currentTime;
}

And use it as normal : const currentTime = useTime()

CevaComic
  • 2,056
  • 2
  • 6
  • 12
  • Are you sure you're getting the time right from the context ? Try console.log(time) in Message component, and check your output. Maybe you're getting something wrong there, I tested your code, and i'm getting undefined on time value. – CevaComic Jun 13 '20 at 23:19
  • oh, sorry, I edited it few minutes later. The time had to be transformed to hours. const time = useContext(GreetingContext); const timeInHours = time.hours(); Also I resolved the issue. The Comment above if interested – Dasha Tiunova Jun 13 '20 at 23:30