Skip to content

albertanguyen/world-clock-reacthook.github.io

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

JayBeta - World Clock React Hook

Created with 💙 by Anh

View online at here.

📘 Lessons Learned

// In React Hook:
// 1hook
  const getBgGradient = (hour) => {
          if (hour < 3) {
            return setGradient('night-2');
        } else if (hour < 6) {
            return setGradient('dawn');
        } else if (hour < 9) {
            return setGradient('morning');
        } else if (hour < 12) {
            return setGradient('afternoon-1');
        } else if (hour < 15) {
            return setGradient('afternoon-2');
        } else if (hour < 18) {
            return setGradient('evening-1');
        } else if (hour < 21) {
            return setGradient('evening-2');
        } else if (hour < 24) {
            return setGradient('night-1');
        };
  }
// 2hook: useEffect(() => getBgGradient(currentHour));

💡 The main idea of Hook is to reduce the syntax: this.<function name> in #2 and #3, and this.setState in #1, using useEffect() to hook the intitial render (componentDidMount()) and also re-render updated DOM (componentDidUpdate()) by a second render. The fundamental flow/life cycle of Reactjs is still the same.

// In normal Reactjs
  1. Update new state (initial state is empty string) for bgGradient ~ Define setGradient function
  setGradient(currentHour) {
      if (currentHour < 3) {
        this.setState({ bgGradient : 'night-2'});
      } else if (currentHour < 6) {
        this.setState({ bgGradient : 'dawn'});
      } else if (currentHour < 9) {
        this.setState({ bgGradient : 'morning'});
      } else if (currentHour < 12) {
        this.setState({ bgGradient : 'afternoon-1'});
      } else if (currentHour < 15) {
        this.setState({ bgGradient : 'afternoon-2'});
      } else if (currentHour < 18) {
        this.setState({ bgGradient : 'evening-1'});
      } else if (currentHour < 21) {
        this.setState({ bgGradient : 'evening-2'});
      } else if (currentHour < 24) {
        this.setState({ bgGradient : 'night-1'});
      }
  }
  2. Mount setGradient
    componentDidMount() {
      this.setGradient(this.state.currentHour);
    }
  3. execute setGradient on DOM ~ componentDidUpdate()
    updateCurrentTime() {
    const { timeZone, currentTime } = this.props;
    this.setGradient(this.state.currentHour);
  }
  • React Hook with API request: The getWeatherInfo() (1hook) ~ #1, getWeatherInfo() (2hook) ~ #2. There is no componentDidUpdate().
// In normal Reactjs
  1.
  async getWeatherInfo(id) {
    const res = await fetch(`https://api.openweathermap.org/data/2.5/weather?id=${id}&units=metric&appid=c5baa00af2bfbc51b5a8bff68a069bb0`).then(res => res.json());
    const weatherInfo = {
      temp: res.main.temp,
      desc: res.weather[0].main,
      icon: `icon-${res.weather[0].icon}`
    };
    this.setState({
      weatherData: weatherInfo
    })
  }
  2.
  componentDidMount() {
    const { weatherId } = this.props;
    this.getWeatherInfo(weatherId);
    this.setGradient(this.state.currentHour);
  }
// In React Hook:
// 1hook.
  const getWeatherInfo = async (id) => {
      const url = `https://api.openweathermap.org/data/2.5/weather?id=${id}&units=metric&appid=c5baa00af2bfbc51b5a8bff68a069bb0`
      const res = await fetch(url).then(res => res.json());
      const weatherInfo = { temp: res.main.temp,
                            desc: res.weather[0].main,
                            icon: `icon-${res.weather[0].icon}`,
                          };
      return setWeatherData(weatherInfo);
  }
// 2hook: useEffect(() => getWeatherInfo(weatherId))

🤐 Describe any challenges encountered while building the app.

  1. First try:
    • Remove node_modules folder, package_log.js
    • npm install
  2. Second try
  3. $ npm install style-loader css-loader autoprefixer-loader sass-loader --save-dev $ sudo npm install --unsafe-perm node-sass
  • Import moment-timezone using ES6 syntax

  • Violate React Hook Rules (from Pre-try): React Hook "useWeatherInfo" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks, meaning cannot be called within other functions (ex: useEffect()) inside React functional component, it is only 1 level down from main React Component.

  1. First try: In order to get access to response from API request within React component, we can make use of setWeatherData to update weatherData. Instead of parsing weatherId to setWeatherData, we create a customed Hook useWeatherInfo() and parse that function to setWeatherData Result: !!!! NO!!! cannot call useWeatherInfo within setWeatherData aka a callback function
  2. Second try: setWeatherData() within API request (getWeatherInfo()) to udpate weatherData with the response from API request. Then mount getWeatherInfo() within useEffect. After that call keys of object weatherData. ===> crashed Firefox browser due to infinite errors ...
  3. Third try: Define getWeatherInfo() using async function then put it inside useEffect() call. After that returning updated weatherData by using setWeatherData within functional React Component.

    Error: weatherData is null.

  4. Fourth try: Probably, the proper flow is update the state by using built-in functions set from useState then return the state like normally doing.

❓ Eventually can I use useState() built-in function set within useEffect, updating the state after render? 💥 Yes, React will re-rendering DOM twice, first by initiating set function inside useEffect() then excute useEffect() after DOM has been updated. This might create infinite loop like I did (see the error message from my below issue). I think we still need to use a separate function for setState by using set function.

  • React Hook useEffect contains a call to 'setGradient'. Without a list of dependencies, this can lead to an infinite chain of updates. To fix this, pass [weatherId, currentHour, currentTime, timeZone] as a second argument to the useEffect Hook react-hooks/exhaustive-deps. I got this error message after my first try, normally we don't need to provide arguments to useEffect if it is put within React Function component since we can access the state variables right from useEffect.

  • window.setInterval is not a function. This is due to this:

useEffect(() => {
  window.setInterval(() => setLocalTime(currentTime.tz(timeZone).format("dddd HH:mm"), 00));
});

The original code:

updateCurrentTime() {
    this.setState({ localTime: currentTime.tz(timeZone).format('dddd HH:mm') });
    };
componentDidMount() {
    window.setInterval(() => this.updateCurrentTime(), 5000);
  };
  • Unhandled Rejection (TypeError): Cannot read property 'data' of undefined.
    Why?
    Because get null object in response.
    Why?
    Because of this (message from console.log()): "Your account is temporary blocked due to exceeding of requests limitation of your subscription type. Please choose the proper subscription http://openweathermap.org/price" 🤐🤐🤐

Version 1.0.0

Rewrite to React Hook from this Reactjs example

Releases

No releases published

Packages

No packages published