DEV Community

bright inventions
bright inventions

Posted on • Updated on • Originally published at brightinventions.pl

I am hooked on React

React has introduced a new feature which allows you to use state and other React feature without writing class, upcoming Hooks, a new proposal in React 16.8.0, which are going to blow your socks off and enable our stateless function component does more than even before!

Initial work

The easiest way to setup environment for learning React with Hooks is run:

npx create-react-app my-app
cd my-app
npm start
Enter fullscreen mode Exit fullscreen mode

Now, we have initialized React application.
Please, make sure that to use the React-Hooks you have installed proper version (the version which I will use is 16.8.0) for today it’s the newest version of React.

If you want to know, which version you are using, please use the command:

npm info react

In case you want to update your react and react-dom please use the command:

npm i react@next react-dom@next

React Hooks

In this post we are going to focus on 3 basic Hooks in React:

useState
useEffect
useContext
Enter fullscreen mode Exit fullscreen mode

React has introduced even more, but the following features are more complicated and should be described separately:

useReducer
useCallback
useMemo
useRef
useImperativeMethods
useLayoutEffect
Enter fullscreen mode Exit fullscreen mode

useState

Now, you can add state to a functional component. We don't need to write a separate class for that.
Let's create a simple counter state-less component and add first Hook.

export const Counter = () => {
   return (
       <div>
           <p>Counter value: </p>
           <button onClick={}>Increase</button>
           <button onClick={}>Decrease</button>
       </div>
   )
}
Enter fullscreen mode Exit fullscreen mode

It's the simple Counter. Our counter will increase and decrease the value if user presses Button onClick event.

The way it works, you can pass the initial state as a first argument, in my case it will be count equal 0.

const [count, setCount] = useState(0);
Enter fullscreen mode Exit fullscreen mode

The useState Hook returns an array. The first entry of the array is the the current value of the state, at this point it will be 0. The second entry of the array is a function to update the state.

Now, we can pass the current value of the state and function for update the state:

export const Counter = () => {
   const [count, setCount] = useState(0);
   return (
       <div>
           <p>Counter value: {count}</p>
           <button onClick={() => {setCount(count + 1)}}>Increase counter</button>
           <button onClick={() => {setCount(count -1)}}>Decrease counter</button>
       </div>
   )
}
Enter fullscreen mode Exit fullscreen mode

useEffect

Hook as ability to avoid the side effects from the function component. It is almost the same like well-known componentDidMount and componentDidUpdate.

So, simply we wll import and add it to our Counter, and pass an anonymous function as a first argument:

const [count, setCount] = useState(0);
const [checked, changeCheckbox] = useState(true)
useEffect(() => {
   console.log('hello from useEffect')
})
Enter fullscreen mode Exit fullscreen mode

For now, the text hello from useEffect will render every time when we change the current value of checkbox (so every time when function flushes changes to the DOM including the first render).

The real power of useEffect is that we can pass a second optional argument, which is an array. Then we can specify that we want to invoke this effect only in the situation when we change the count value.

useEffect(() => {
   console.log('hello from useEffect')
}, [count])
Enter fullscreen mode Exit fullscreen mode

Now, the useEffect will be called only in case that the state of the count will change. Cool, right?

useContext

Imagine, the problem is that the name and surname of user from an index file is passed down as a prop to the components.

We are going to create two additional function components: Header and LoginInfo. The components will only render the value passed as a prop from the Dashboard.

Dashboard which actually does not use it, just passed it down to Header which uses the value from the user state and passes it as well to LoginInfo which also renders the name of the user.
This approach is ok, but we have to pass a user through a bunch of components (in our case Dashboard which doesn't care about it).

One way to make it looks better is to use createContext, to create a new context and returns the current context value, as given by the nearest context provider for the given context.
So let's create and export the Context object:

import React from 'react'
const Context = React.createContext()
export default Context
Enter fullscreen mode Exit fullscreen mode

In our index app, we are importing the Context and wrap the whole main page component with <Context.Provider> and pass the user value from state as a prop. Now, we have an access to all of the
Context consumers to the value from state and we don’t need to pass it through the components as a prop.

import React, { Component } from 'react';
import './App.css';
import { Dashboard } from "./Dashboard";
import Context from './Context'

class App extends Component {
   state = {
       user: 'John Doe'
   }
   render() {
       const {user} = this.state
       return (
           <Context.Provider value={user}>
               <Dashboard />
           </Context.Provider>
       );
   }
}
export default App;
Enter fullscreen mode Exit fullscreen mode

Right now, we use useContext Hook and wrap our Context, where the value is a value passed from the Provider (our index). Let's assign in to user variable.

import React, { useContext } from 'react'
import LoginInfo from './LoginInfo'
import Context from './Context'

const Header = () => {
    const user = useContext(Context)
    return (
        <div>
            <h1>Welcome {user}</h1>
            <LoginInfo />
        </div>

    )
}

export default Header
Enter fullscreen mode Exit fullscreen mode

The situation will be the same for the LoginInfo. We declare a value user by using useContext Hook and the value is a value passed from the Provider (our index).

import React, { useContext } from 'react'
import Context from './Context'

const LoginInfo = () => {
    const user = useContext(Context)
    return (
        <h6>Logged as {user}</h6>
    )
}

export default LoginInfo
Enter fullscreen mode Exit fullscreen mode

In LoginInfo and Header now we have prop user as a value, so we can remove the unnecessary prop from the Dashboard which doesn't use it at all.

React Hooks restrictions

Although it looks nicely, it's really good to know about Hooks:

  • Hooks can be only called from React function component,
  • Hooks should be only called on the top level. Don't call them inside loops, conditions or nested functions. By following this rule, you ensure that Hooks are called in the same order each time as component renders. That's what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls. (For more if you are curious, good explain is here).

Class base component will be no more support?

I think that Hooks and class base components will be still useful. The documentation says that "There are no plans to remove classes from React" and they definitely do not recommend rewriting everything into Hooks. It's individual and you should decide whether use Hooks or Classes.

Hooks are great feature in React. Personally, I'm using it after stable version release.

Originally published at brightinventions.pl

By Patryk Huzarski, Software Engineer @ Bright Inventions
Email

Latest comments (2)

Collapse
 
trojano31 profile image
Patryk Trojanowski

What's great about hooks is that you can create a custom one and share it across many components in the app!

Collapse
 
mcrowder65 profile image
Matt Crowder

Hey! In your markdown you should add js after the backticks, and that will add code highlighting. If you don’t want it, then disregard :)