Created with 💙 by Anh
View online at here.
- Import scss to react project.
- how to locate webpack.config.js
- Using momentjs and moment-timezone
- API request with React Hook
- Instead of thinking of useEffect as mounting and updating, useEffect happens after render. React makes sure the DOM has been updated by the time it runs useEffect. Before, DOM is first rendered by render function, side effects are initiated and executed by componentDidMount and componentDidUpdate. As per my understanding, render function now is the first return from React Function component. After that useEffect will execute other functions to update the DOM.
- The
getBgGradient (1hook) ~ #1,
getBgGradient()
inuseEffect()
(2hook) ~ #2 and #3
// 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 nocomponentDidUpdate()
.
// 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))
To import Sass files, you first need to install node-sass. Run
npm install node-sass
oryarn add node-sass
inside your workspace.- Permission denied while installing node-sass. Solution:
- First try:
- Remove node_modules folder, package_log.js
npm install
- Second try
$ npm install style-loader css-loader autoprefixer-loader sass-loader --save-dev
$ sudo npm install --unsafe-perm node-sass
-
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.
- 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
- 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 ...
- 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.
- 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 fromconsole.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"
🤐🤐🤐
Rewrite to React Hook from this Reactjs example