DEV Community

Harry J Beckwith
Harry J Beckwith

Posted on

8 3

React learning guide

Alt Text

How do you go about learning React?

  • Find a list of core concepts in react. (see list below)
  • Write small code examples for each with a written description on what is going on.
  • Combine all the small examples into a working application.

What is React?

  • React is a javascript library for building user interfaces.
  • A client-side javascript library.
  • All about building modern reactive user interfaces for the web.
  • Declarative, component focused approach.

How does react work?

React creates a virtual DOM which means changes can be made to the UI and only that specific part that was updated not the whole page.

What is declarative code?

  • is a way to write code that describe what you want to do.
  • rather than imperative which is how you do something.

What is JSX?

  • JSX is javascript and XML combined meaning you can write html inside javascript. This allows you to write components in React easily.

State vs props

  • State is used to handle data in the application which will be reactive and update in turn then update the UI.

  • Props are used to pass data/or state through to other components in the application that react to the state update.

What is reactDOM?

  • is a package that provides DOM (document object model) specific methods. These methods can be used to manage the DOM in an effective easy way.

Explain hooks?

  • Hooks are a new addition in React 16.8. This is a move away from class based components. You can access the state by using a hook called useState. Some of the main hooks are useState, useEffect, useContext, useReducer and useRef. There are a few more also.

What is Redux?

  • Redux is a state management library for React. It allows you to centralise state in once place rather passing state through multiple components.

Core concepts

useState

import { React, useState } from 'react';
function App() {
const [count, setCount] = useState(1)
const countIncrease = () => {
setCount(count + 1)
}
const countDecrease = () => {
setCount(count - 1)
}
return (
<div>
{count}
<button onClick={countIncrease}>Increase counter</button>
<button onClick={countDecrease}>Decrease counter</button>
</div>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub

The above gist

line 1: we import useState
line 4: we use array destructuring, count is our state setCount is the function we use to update the state.
line 4: 1 is passed into useState this is are starting state
line 7: setCount is called passing the starting state count plus 1
line 16: count is placed into the JSX
line 17: onClick is used to call the function that updates our count

prevState

import { React, useState } from 'react';
function App() {
const [stateObject, setStateObject] = useState({
firstKey: '',
secondKey: ''
})
const updateKey = () => {
setStateObject((prevState) => {
return {
...prevState,
secondKey: 'hello'
}
})
}
return (
<div>
{stateObject.secondKey}
<button onClick={updateKey}>click me</button>
</div>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub

The above gist

line 4: we set our state to and object
line 9: function to update state
line 10: we use prevState as we want to keep the previous state and update only part of the object
line 13: we use the spread operator to create a copy of the object
line 14: we select the key we want to update, and change the value
line 19 down: we click to call the function and update the key displaying it to the DOM.

The above, prevState is used so we keep the old state and update only the selected value.

props

props are used to pass information (state or other) to components and share this information. Once the source of the props is updated all components using this prop will then update.

import HelloWorld from './components/HelloWorld'
function App() {
return (
<div>
<HelloWorld message="hello world!"/>
</div>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub
const HelloWorld = props => {
return props.message
}
export default HelloWorld
view raw HelloWorld.js hosted with ❤ by GitHub

line 7: message prop name is set to a string hello world!
HelloWorld.js takes props and returns the props.message

Lifting up state

import {React, useState } from 'react'
import Button from './components/Button'
function App() {
const [message, setMessage] = useState('')
const handleUpdateMessage = (props) => {
setMessage(props)
}
return (
<div>
{message}
<Button updateMessage={handleUpdateMessage}/>
</div>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub
const Button = props => {
const handleButtonClick = () =>{
props.updateMessage('hello!')
}
return (
<button onClick={handleButtonClick}>Update message</button>
)
}
export default Button
view raw Button.js hosted with ❤ by GitHub

The above gist

line 6: state is set
line 8: function that updates state
line 15: Button component, updateMessage set to the handleUpdateMessage function

Button.js

line 3: click event from the pass props handleButtonClick
line 4: we access the parent function through props, passing in the message hello!

Button is clicked now the parent App.js updates the state, line 14: now shows the hello message.

useRef

import {React, useRef, useState } from 'react'
function App() {
const [message, setMessage] = useState('')
const userInput = useRef()
const handleInput = () => {
setMessage(userInput.current.value)
}
return (
<div>
{message}
<input type="text" ref={userInput} onChange={handleInput}/>
</div>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub

Use ref can be used to reference input fields and get the value from the input.

Above gist

line 1: useRef is imported
line 6: we store useRef() in a const
line 15: ref is set the useRef const
line 9: we access the value from the input. using .current.value
line 9: state is updated, message is updated in the DOM.

Fragments

Avoid div soup and write cleaner html. React allows one root DOM element. This means sometimes using div where it's not really needed. Fragments solve this.

Without fragment

import {React} from 'react'
function App() {
return (
<div>
<p>Hello</p>
<p>world</p>
</div>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub

With Fragment

import {React, Fragment} from 'react'
function App() {
return (
<Fragment>
<p>Hello</p>
<p>world</p>
</Fragment>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub

Forward refs

Refs cannot be used when adding the ref tag to a component. In order to use refs when passing to a child component you can use forwardRefs.

import {React, useRef} from 'react'
import InputText from './components/InputText'
function App() {
const ref = useRef()
function focus() {
ref.current.focus();
}
return (
<div>
<InputText ref={ref}/>
<button onClick={focus}>Focus</button>
</div>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub
import {React, forwardRef} from 'react'
const InputText = forwardRef((props, ref) => {
return <input ref={ref} type="text" />
})
export default InputText
view raw InputText.js hosted with ❤ by GitHub

Above gist

App.js

Line 1: import useRef
Line 2: import import component
Line 5: create useRef
Line 8: focus on the input with ref
Line 13: add pass ref to child component

InputText.js

Line 1: import forwardRef
Line 3: Wrap component in forwardRef function, pass props and ref as required
Line 4: set the ref to the input

Now back in App.js we on click

Line 14: we set the focus to the child input.

Use effect

Use effect is a way to call code on page and respond to any updates inside the use effect method, calling the code again.

Im not sure if the above made much sense. However it's a method that is used for when the component is mounted and when an effect triggers the code inside the use effect method.

Let's look at an example. This example is an email and password login. We want to check on page load if the user is logged in.

Using useEffect we can check local storage for logged in user.

import React, { useState, useEffect } from 'react';
import Login from './components/Login/Login';
import Home from './components/Home/Home';
import MainHeader from './components/MainHeader/MainHeader';
function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
const storedUserLoggedInInformation = localStorage.getItem('isLoggedIn')
if(storedUserLoggedInInformation === '1') {
setIsLoggedIn(true)
}
},[])
const loginHandler = (email, password) => {
// We should of course check email and password
// But it's just a dummy/ demo anyways
setIsLoggedIn(true);
localStorage.setItem('isLoggedIn', '1')
};
const logoutHandler = () => {
setIsLoggedIn(false);
};
return (
<React.Fragment>
<MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
<main>
{!isLoggedIn && <Login onLogin={loginHandler} />}
{isLoggedIn && <Home onLogout={logoutHandler} />}
</main>
</React.Fragment>
);
}
export default App;
view raw App.js hosted with ❤ by GitHub

The above gist has a few things going on. But we only need to focus on line 10 for now.

Inside we check for local storage item, if its then we update the state.

What this allows us to do is, on page refresh we can fire the useEffect method - checking local storage. if true then we update the state to so the user is logged in.

useEffect dependencies

Use effect takes an array as the second argument. In here the dependencies that are being updated (state should be passed in ) this way react knows which state to look out for changes and fire the function again.

The below gist shows a login screen, the useEffect function takes the two dependencies as array items. Now if either update the function is called again.

Gist showing useEffect dependencies

import React, { useState, useEffect } from 'react';
import Card from '../UI/Card/Card';
import classes from './Login.module.css';
import Button from '../UI/Button/Button';
const Login = (props) => {
const [enteredEmail, setEnteredEmail] = useState('');
const [emailIsValid, setEmailIsValid] = useState();
const [enteredPassword, setEnteredPassword] = useState('');
const [passwordIsValid, setPasswordIsValid] = useState();
const [formIsValid, setFormIsValid] = useState(false);
useEffect(() => {
setFormIsValid(
enteredEmail.includes('@') && enteredPassword.trim().length > 6
);
}, [enteredEmail, enteredPassword])
const emailChangeHandler = (event) => {
setEnteredEmail(event.target.value);
};
const passwordChangeHandler = (event) => {
setEnteredPassword(event.target.value);
};
const validateEmailHandler = () => {
setEmailIsValid(enteredEmail.includes('@'));
};
const validatePasswordHandler = () => {
setPasswordIsValid(enteredPassword.trim().length > 6);
};
const submitHandler = (event) => {
event.preventDefault();
props.onLogin(enteredEmail, enteredPassword);
};
return (
<Card className={classes.login}>
<form onSubmit={submitHandler}>
<div
className={`${classes.control} ${
emailIsValid === false ? classes.invalid : ''
}`}
>
<label htmlFor="email">E-Mail</label>
<input
type="email"
id="email"
value={enteredEmail}
onChange={emailChangeHandler}
onBlur={validateEmailHandler}
/>
</div>
<div
className={`${classes.control} ${
passwordIsValid === false ? classes.invalid : ''
}`}
>
<label htmlFor="password">Password</label>
<input
type="password"
id="password"
value={enteredPassword}
onChange={passwordChangeHandler}
onBlur={validatePasswordHandler}
/>
</div>
<div className={classes.actions}>
<Button type="submit" className={classes.btn} disabled={!formIsValid}>
Login
</Button>
</div>
</form>
</Card>
);
};
export default Login;
view raw Login.js hosted with ❤ by GitHub

useReducer

Sometimes you have more complex state - for example if it got multiple states, multiple ways of changing it or dependencies to other states.

more powerful state management.

More complex to use.

good replacement for useState when you have state that belongs together.

import React, { useReducer } from 'react';
function App() {
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
export default App;
view raw app.js hosted with ❤ by GitHub

useReducer takes two arguments, a function and the initial state.

The variable name dispatch calls the reducer function, which in turn updates the state.

Using this methods allows us to handle complex logic in the reducer function.

Conclusion

That's some of the core basic concepts, with small examples. The trick now is too combine to create a small application.

Link to follow showing a small project with core basic concepts. Thanks.

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay