hooks

Today

We are going to learn another hook from React. Where useState() we learnt yesterday help us control the re-render of the UIs , the next hook - useEffect() help us to control coordinate "side effects" with the state of the component during it life cycle.

The useEffect Hook lets you perform side effects in function components

So, what is the side effect in a function?

A side effect is any execution that affects something outside the scope of the function being executed. It is not a React specific term, it's a general concept about the behavior of a function.

Some examples of side effects in React components are:

For example, this component sets the document title after React updates the DOM:

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

function Example() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

So, when you call useEffect, you're telling React that your component needs to do something after render. React will remember the function you passed (we'll refer to it as our "effect"), and call it later after performing the DOM updates.

Why is useEffect called inside a component? Effects are declared inside the component so they have access to its props and state (count state variable)

Does useEffect run after every render? By default, React runs the effects after every render — including the first render.

Syntax of useEffect

useEffect() hook is a special function that accepts 2 arguments:

useEffect(callback,[dependencies]);

The order of executions

Let's check out one more example to really understand the order when we use useEffect

function App() {
  let [userCount, setUserCount] = useState(0);
  
  useEffect(() => {
      alert("Component updated")
  });
  
  const handleOnClick = ()=>{
      setUserCount(userCount + 1)
  }
  return (
    <div>
      <p>User Count: {userCount}</p>
      <button onClick={handleOnClick}>
        Add employee
      </button>
    </div>
  );
}

In the code above, at the first render, we see that the alert message will appear after the content render on the page. After that, whenever the user clicks the button, the state variable, userCount will be incremented by one. As soon as the state variable updates, the react component will be re-rendered. After each re-rendering, useEffect will be re-invoked, which lead to the relevant DOM element (the p tag in this case) is updated and we get an alert notifying us that the component has been updated

Dependecies array

The callback we're passing to useEffect is called after every render of our component (including re-renders). In some cases, applying the effect after every render might create a performance problem.

Example: Now, let's build a component that will render to the DOM an input and a div that render the number of changes that we have made in the input.

import { useEffect, useState } from 'react';

function App() {
  const [value, setValue] = useState("");
  const [count, setCount] = useState(-1);
  useEffect(() => {
    setCount(count + 1);
  });

  const handleChange = (event) => {
    setValue(event.target.value);
  };
  return (
    <div>
      <input type="text" value={value} onChange={handleChange} />
      <div>Number of changes: {count}</div>
    </div>
  );
}

Try the code above and see what happen? . . .

Ok, with the code above, when the component re-renders due to user typing into the input, the useEffect(() => setCount(count + 1)) updates the count state.

Remember that: When the state change, our Component will be rerender. And whenever the Component render, the useEffect will run

How to fix this? Simply put a dependencies array in as a second argument.

useEffect(() => setCount(count + 1),[value])

This will stop the loop!! Now, let have a look closer to dependencies array.

There are 3 cases we can see with the dependencies array. When dependencies are:

  1. Not provided: the side-effect runs after every rendering.(the example code above) Without the dependencies array, the callback function will execute after every render — including the first render.
  2. An empty array []: the side-effect runs once after the initial rendering.
import { useEffect, useState } from 'react';

function App() {
  const [value, setValue] = useState('');
  const [count, setCount] = useState(-1);
  useEffect(() => {
      setCount(count + 1)
  },[]);
  
  const handleChange = (event) => {
      setValue(event.target.value);
  }
  return (
    <div>
      <input type="text" value={value} onChange={handleChange} />
      <div>Number of changes: {count}</div>
    </div>
  )
}
  1. Has props or state values [prop1, prop2, ..., state1, state2]: the side-effect runs only when any depenendecy value changes.
import { useEffect, useState } from 'react';

function App() {
  const [value, setValue] = useState('');
  const [count, setCount] = useState(-1);
  useEffect(() => {
      setCount(count + 1)
  },[value]);
  
  const handleChange = (event) => {
      setValue(event.target.value);
  }
  return (
    <div>
      <input type="text" value={value} onChange={handleChange} />
      <div>Number of changes: {count}</div>
    </div>
  )
}
module export App

The scenario

We have an API endpoint to fetch data that is

let url = "https://newsapi.org/v2/everything"; 
// and some enpoints

/**
https://newsapi.org/v2/everything?q="tea" 
https://newsapi.org/v2/everything?q="milk" 
https://newsapi.org/v2/everything?q="coffee" 

*/

Let's break it down into small steps

  1. Create a state to hold our current query
  2. Create a state to hold our current title
  3. Create a change query handler function
  4. Create a fetch data function according to query
  5. 3 buttons with different value
  6. A heading to see our current title
  7. Execute the fetch data function whenever the category state change

Here is the first 6 steps:

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

const API_KEY="97a8df3625884a2da87308f934ecfbbd" //get your own key from newsapi.org

const App = () => {
  const [query, setQuery] = useState("");
  const [title, setTitle] = useState("")
  
  const getData = async () => {
      let url = "https://newsapi.org/v2/everything";
      url += `?q=${query}&apiKey=${API_KEY}`;
      console.log(query)
      
      const res = await fetch(url);
      const data = await res.json()
      console.log("all news: ", data);
      };

  const handleQuery = (event) => {
    setQuery(event.target.value);
  };

  return (
    <>
      <h1>{title}</h1>
      <h2>{query}</h2>
      <button id="btn1" onClick={handleQuery} value="tea">
        Tea
      </button>
      <button id="btn2" onClick={handleQuery} value="milk">
        Milk
      </button>
      <button id="btn3" onClick={handleQuery} value="coffee">
        Coffee
      </button>
    </>
  );
};

export default App;

If we run the code above, we would see three button. If we click any of the button we would see the h2 change the value accordingly. We haven't make any API calls which would have result in the getData function executed thus the console.log with I will get data from the url.

So now, we implement step 6: try to execute the getData function after change the query state variable with useEffect()

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

const API_KEY="97a8df3625884a2da87308f934ecfbbd" //get your own key from newsapi.org

const App = () => {
  const [query, setQuery] = useState("");
  const [title, setTitle] = useState("")
  useEffect(()=>{
      const getData = async () => {
          let url = "https://newsapi.org/v2/everything";
          url += `?q=${query}&apiKey=${API_KEY}`;
          
          const res = await fetch(url);
          const data = await res.json()
          console.log("all news: ", data);
          
          setTitle(data.articles[0].title)
      };
      getData()
  },[query])
  

  const handleQuery = (event) => {
    setQuery(event.target.value);
  };

  return (
    <>
      <h1>{title}</h1>
      <h2>{query}</h2>
      <button id="btn1" onClick={handleQuery} value="tea">
        Tea
      </button>
      <button id="btn2" onClick={handleQuery} value="milk">
        Milk
      </button>
      <button id="btn3" onClick={handleQuery} value="coffee">
        Coffee
      </button>
    </>
  );
};

export default App;

First, let's test it without the weird array above, what would you see? It works, right? We're able to solve the first problema about the "late" update. But look at your console, it still run the getData function when we click to the same button. So it works but we need to optimized the code. That's why we need that weird array which called dependencies array

The following read is pretty cool regarding our today topics.

An old enemy, but this time, we come prepared and equiped with React Js.

Description

Techs

Front End

Back End

Create react app

mkdir react-coder-news
cd react-coder-news
npx create-react-app .

Pray to React god untill we see happy hacking

Front-end framework

React Bootstrap

React Bootstrap

npm install react-bootstrap
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
  integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
  crossorigin="anonymous"
/>

We have the file structure:

|-node_modules/
|-public/
  |-index.html
|-src
  |-App.js
  |-index.js
  |-App.css
.env
.gitignore
pakage-lock.json
package.json
README.md

Planning

It is important to understand the structure of our data before start coding. The benefits of using an external API like NewsApi are well documented, tested and ready to use.

The strategy here is to map the required features with the provided API endpoints before we start coding. So that we would have a clear vision of what would be our main focus.

Features

Endpoint

User see 20 news

https://newsapi.org/v2/everything&apiKey=key

User filter with Category

https://newsapi.org/v2/top-headlines?category=&country=us&apiKey=key

User can search (basic)

https://newsapi.org/v2/everything?q=category>&apiKey=key

User can use Pagination

https://newsapi.org/v2/everything?page=page &apiKey=*key

As we can see after list out all the endpoints that would be used, we could also list out the list of variables that will be change according to use cases.

They are :

Security

Internet is a dangerous place. API keys eventhough free, sometime contain info that should not be leak. For examples, we probaly dont want me to use up all our API-call-allowance before our demo day, right?. Would not be fun at all not be able to call any data in our final project. So how will an API key leak? If we put it in our code, it is visible to the internet.

It is recommended to keep all our keys and password in .env file. Then also use .gitignore to prevent pushing online to github. So let do that. In our .env, add

REACT_APP_API_KEY=ourKey
const apiKey = process.env.REACT_APP_API_KEY;
//test
console.log(apiKey);

Again, before starting to code. We should identify what would be our file structure. We will think about our components tree. We assume that we could create any components (we hope) perfectly. Then with that assumption, we design the component tree so that we could distinguish which component do what task. Which is statefull? which is stateless? Where should we trigger fetch data? ...

With all the hints above so let's now build the app.

Given this suggested components tree

src/
|- App.js
|- index.js
|- Components/
 |- SideMenu.js
 |- MainPage.js
 |- Pagination.js
 |- SearchBox.js

Now, form what we have learnt it's your turn to build up a news page.

Requirements

Bonus