By: Alan Nguyen
Table of Contents
- React - Treehouse
#Add React to a Project
Q. React manipulates and updates the DOM directly?
- React only manages what gets rendered to the DOM via
ReactDOM.render
. It’s the job ofrender()
to interpret the element objects and create DOM nodes out of them.
#Understanding JSX
#Embed JS expressions in JSX
Q. Elements written in JSX get transpiled to?
React.createElement()
functions
#What is a Component?
- A piece of UI that you can reuse.
- Just like you're able to reuse code in JavaScript with functions, a component lets you reuse code that renders a part of your UI.
- Being able to split your UI code into independent, reusable pieces, and think about each piece in isolation is one the most embraced features of React.
#Create a Component
While it isn’t required, the React docs recommend wrapping multiple lines of JSX in ()
to avoid the pitfalls of automatic semicolon insertion.
#Use a Component with JSX
- JSX lets you define your own tags. A JSX tag can not only represent an HTML element (like
<h1>
,<span>
, and<header>
), it can also represent a user-defined component.
React components are written in plain JS with the help of JSX
#Composing Components
#React Developer Tools
With React, we never touch the actual DOM directly. React only manages what gets rendered into the DOM, so it can be tricky to debug your UI in the browser. The React Developer Tools extension gives you a big productivity boost when working with React. It lets you inspect your React component hierarchy in the Chrome and Firefox Developer Tools.
Q. Why is a capital letter necessary in the component name?
- To differentiate custom components from native DOM elements (
div
,span
)
#Setting and Using Props
Props
- a list of properties used to pass data to a component. Components are customized and made reusable with props.
Two Steps to using props in components
- Define the props in a component’s JSX tag
- Enable the use of props in a component
props
are read only (immutable)- The (parent) component higher in the tree owns and controls the property values
All React components must act like pure functions with respect to their
props
- You can omit the value of a prop when it's explicitly true
<Header isFun />
#Use Props to Create Resuable Components
#Iterating and Rendering with map()
- render multiple items
#Use Keys to Keep Track of Elements
-
Key
is a unique identifier that gives React a way to quickly and reliably identify an element in the list -
React manages what gets rendered to the DOM. In order for this process to be fast and efficient, React needs a way to quickly know which items were changed, added, or removed. For this, React gives elements a special built-in prop named key. A key is a unique identifier that gives React a way to quickly and reliably identify an element in a list.
-
React does not recommend using index for unique keys, because the index might not always uniquely identify elements. It's usually best to use a unique id.
According to the React docs:
We don’t recommend using indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state. Check out Robin Pokorny’s article for an in-depth explanation on the negative impacts of using an index as a key. If you choose not to assign an explicit key to list items then React will default to using indexes as keys.
#What is State
State
is the data you want to track in your app. State is what allows you to create components that are dynamic and interactive, and it's the only data that changes over time.
Note: State is only available to class component
#Create a Component as a class
- Class components offer a more powerful way to build components because they're the only type of components that let you use state.
- In class, access props by this.props
- Use class instead of function when you want to use State
#Create a stateful component
- create a stateful component by first defining an initial state inside the Counter class.
class Counter extends React.Component {
constructor() {
super();
this.state = {
score: 0,
};
}
}
- a shorter way to create state (feature of JS is currently not suppoted in all browers but babel transpiler helps to convert it to constructor)
class Counter extends React.Component {
state = {
score: 0,
};
}
#Handling events
To make the Counter component interactive, we need to be able to trigger changes to the data in state.
- We'll first create an event handler that updates state, using React's built-in
setState()
method. - Then we'll give the buttons an
onClick
event that calls the event handler when clicked.
#Updating state
- In React, state is never modified directly. The only way React allows you to update a component's state is by using its built-in
setState()
method.
incrementScore() {
this.setState({
score: this.state.score + 1
})
}
#Bind event handlers to components
- When you create a class component that extends from React.Component, any custom methods you create are not bound to the component by default. You need to bind your custom methods, so that
this
refers to the component instance.
Several ways of binding:
onClick={this.incrementScore.bind(this)}
- arrow function inside
render
- it uses a lexical this binding which automatically binds them to the scope in which they are defined
- arrow function inside class
incrementScore = () => {
this.setState({
score: this.state.score + 1
})
}
onClick={this.incrementScore}
- Another way to bind an event handler is in the class constructor
constructor() {
super();
this.state = {
score: 0,
};
this.incrementScore = this.incrementScore.bind(this);
}
onClick={this.incrementScore}
#Update state based on previous state
-
Whenever you need to update state based on previous state, you shouldn't rely on
this.state
to calculate the next state. State updates may be asynchronous, so it may not always lead to the component re-rendering with new data, and could cause state inconsistency. -
setState()
accepts a callback function that produces state based on the previous state in a more reliable way. -
Update state using callback function
incrementScore = () => {
this.setState(prevState => {
return {
score: prevState.score + 1,
};
});
};
- More concise way
incrementScore = () => {
this.setState(prevState => ({
score: prevState.score + 1,
}));
};
#Creating the application state
- Now you're going to learn how to remove items from state. We'll initialize a players state in the App component, then create and wire up an event handler that removes a player onClick.
2 types of states
- Application state (data available to the entire app)
- Component state (state that is specific to a component and not shared outside of the component)
#Remove items from state
- use the
filter()
array iteration method to remove an object from the players array in state.
_Note: Never modify state directly (commonly use filter array) _
#Setting up with Create React App
- Developers normally use Create React App for developing React applications because it lets you quickly create and run React apps with no configuration.
- Create React App is well-suited for projects of any size, and often used for developing production-ready apps.
Steps
npx create-react-app projectName
npm install
_ to install in dependencies_
Why Create React App?
- The CDN-based approach is not useful in a production environment as soon as you start using JSX. For instance, we used Babel directly in the browser to transpile JSX into JavaScript. The Babel script is ~800KB in size, which for most use cases, is too large of a download to be practical. Also, there's the overhead in the browser of transpiling JSX into JavaScript.
- Developers use compiling as part of a build process to avoid the overhead of downloading Babel and multiple JavaScript files to the client. Create React App sets up a modern build system for your React apps in little time, no need to install or configure tools like Webpack or Babel. The tools are already pre-configured in each new project, that way you can focus on building your app.
Q. What's in package.json?
- When you create a project with Create React App, it installs the latest version of React and React-DOM, as well as the latest version of react-scripts, a development dependency that manages all other dev dependencies that run, test and build your app.
Progressive Web App Features
- Create React App sets up a fully functional, offline-first Progressive Web App by default. However, we removed the PWA related files just for this project to focus on the React components only.
#Separating function components into Modules
- Each component should be a separated component
#Separating class components into Modules
- break the Counter class out into its own module. We'll also use named import statements to define a class without having to extend from
React.Component
.
Import React, Component
import React, { Component } from 'react';
import Header from './Header';
Export component
export default Counter;
Another way to export a class
export default class Counter extends Component {
render() { ... }
}
Another way to export a function
export const Counter = () => {
return ( ... );
}
#Unidirectional Data Flow
In React, data naturally flows down the component tree, from the app's top-level component down to the child components, via props. This is called "unidirectional data flow".
#Lifting State Up
When two or more components need access to the same state, we move the state into their common parent. This is called "lifting state up".
#Update state based on a Player’s index
- writing the
handleScoreChange
function by updating state based on the index of a player object.
#Building the statistics component
We lifted the score state up to the top of the application. Now we can pass that state down to any component. We'll build a statistics component that displays the total number of players on the Scoreboard, as well as the total number of points.
#Controlled components
To manage an input field's state, we need to build a "controlled component." A controlled component renders a form element whose values are controlled by React, with state.
Creating a controlled component
- listen for changes on the input to detect when value is updated
- create an event handler that updates the value state
class AddPlayerForm extends Component {
state = {
value: '',
};
handleValueChange = (e) => {
this.setState({ value: e.target.value});
}
render() {
return (
<form>
<input
type="text"
value={this.state.value}
onChange={this.handleValueChange}
/>
</form>
)
}
}
#Adding items to state
-
create an event handler that allows users to submit the form. Then we'll write a function that adds the new player to state and displays it in the UI.
-
handle submit
handleSubmit = (e) => {
e.preventDefault();
this.props.addPlayer(this.state.value);
this.setState({value: ''});
}
render() {
return (
<form onSubmit={this.handleSubmit}>
- handle add player
handleAddPlayer = (name) => {
this.setState((prevState) => {
return {
players: [
...prevState.players,
{
name,
score: 0,
id: (this.prevPlayerId += 1),
},
],
};
});
};
#Update the players state based on previous state
Note: should use prevState
instead of this.state
when we want to update the state. That way we can be sure that this.state
always holds the correct updated state.
- Update the
players state
using theconcat()
method
handleAddPlayer = (name) => {
let newPlayer = {
name,
score: 0,
id: this.prevPlayerId += 1
};
this.setState( prevState => ({
players: prevState.players.concat(newPlayer)
}));
};
Q. React allows us to use props that are callback functions to communicate data upstream, from a child to a parent.
- That’s how a child component can access functions and change state defined in its parent component
#Designing the Stopwatch
- It will be a stateful component that counts seconds, and allows users to start, stop and reset the time.
#Stopwatch State
The stopwatch will have two main states visible to the user. It will be either in a running state, or a stopped state. The buttons on the interface should change based on the running state. We'll start by initializing state in the Stopwatch component.
Conditional rendering with if...else
render(){
let button;
if (this.state.isRunning){
button = <button>Stop</button>;
} else {
button = <button>Start</button>;
}
}
return (
{ button }
)
#Update the Stopwatch State with componentDidMount()
Component Lifecycle - every component instance follows a cycle:
- mounted onto the DOM
- updated with changes in data
- unmounted from the DOM
React lifecycle methods
- built-in methods that get called at each point in the life cycle
- hooks that run code at key times in a component's life cycle
- give the ability to control what happens when a component mounts, updates and unmounts
Use the componentDidMount()
lifecycle method to make the stopwatch tick. React's built-in lifecycle methods get called at each point in a component's life-cycle. The methods act as hooks you can use to run code at key times in the life-cycle. This gives you the ability to control what happens when a component mounts, updates and unmounts.
#Resetting the Stopwatch
In order to display the stopwatch time in seconds, we'll do one final calculation that converts the elapsed time in milliseconds to seconds. Then we'll wire up the "Reset" button to a function that resets the stopwatch back to 0.
#Prevent Memory Leaks with componentWillUnmount()
Since components do not always stay in the DOM, React also provides the componentWillUnmount
lifecycle method to help you handle unmounting of components. This can help prevent memory leaks in your application.
Q. Which lifecycle method gets called by React as soon as a component is inserted into the DOM?
- componentDidMount()
Q. Which lifecycle method do you use to fetch data from an API?
- componentDidMount()
#Optimize Performance with PureComponent
React provides a special type of component, called PureComponent, that helps prevent unnecessary re-renders. If your component’s render()
method renders the same result given the same props and state, you can use PureComponent for a performance boost in some cases.
React Component Patterns
- Destructure props
- Validate props
- Access DOM nodes with refs
- Practice creating React components
- Use PureComponent
Note: A PureComponent
should only contain child components that are also PureComponents.
#Destructuring Props
ES2015 introduced destructuring assignment, which is a special kind of syntax you can use to "unpack" (or extract) values from arrays, or properties from objects, into distinct variables. Developers often use destructuring in React to make their components cleaner and easier to understand. It provides a more concise way to write your props.
- destructure props to players and title
const Header = ({ players, title }) => {
return (
<header>
<Stats players={players}/>
<h1>{title}</h1>
</header>
);
};
-
another way to destructure
const { players, title } = props;
#Refs and the DOM
Refs let you access and interact with DOM nodes created in the render()
method. They make it possible to do the more traditional DOM manipulation, and they're commonly used to access form elements and get their values.
When to use Control component and Ref?
-
Control component - easier to modify or validate user input, call render on every key stroke
-
Ref - render is called only once, use when don’t have to keep track every key stroke, just the value from DOM
playerInput = React.createRef();
handleSubmit = (e) => {
e.preventDefault();
this.props.addPlayer(this.playerInput.current.value);
e.currentTarget.reset();
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
type="text"
ref={this.playerInput}
/>
#Validate Props with PropTypes
As your app grows, it's a good practice to "type check" or validate the data a component receives from props. In this video, you'll learn how to validate props with the PropTypes
library. PropTypes
not only help you catch and avoid bugs, they also serve as a documentation for components. Other developers working on the same project will know exactly which props your components take, and what types they should be.
npm install --save prop-types
Type checking in React
- PropTypes
- TypeScript
- Flow
import PropTypes from 'prop-types';
Header.propTypes = {
title: PropTypes.string,
player: PropTypes.arrayOf(PropTypes.object),
};
#Static PropTypes and Default Props
In class components, it's common to define propTypes
inside the class with the static keyword. You can also set a default value for your props, with a defaultProps
object.
import PropTypes from 'prop-types';
class Player extends PureComponent {
static propTypes = {
index: PropTypes.number,
isHighScore: PropTypes.bool,
};
#Expand your React Skill
Routing is the process of matching a URL to the set of components being rendered. Routing dynamically loads components and changes what's displayed in the browser as users navigate an app, all without reloading the page. React does not have built-in routing features, so developers rely on React Router, an external library designed specifically for React.
#What is Routing?
In single-page apps (SPAs), routing is responsible for loading and unloading content while matching the URL with the set of components being rendered. Routing should also keep track of browser history and link users to specific sections of your app.
Q. A good routing solution should keep track of browser history and seamlessly link users to specific sections of your app.
- True. Users should navigate a single-page app using the browser’s back and forward buttons, and URL should always direct the user to the correct location
Q. In web development, routing:
- Matches a URL to the set of components being rendered
Q. React Router does not let you change routes programmatically. For example, you are not able to create a route in response to a form submission - False
Q. What is a single-page app (SPA)?
- A web application that display on a single web page. The HTML, JS, and CSS are loaded once by the browser and the content changes dynamically as users interact with the app
Q. React includes built-in routing features.
- False. React is a libarary concerned with just rendering your UI. You’ll install additional libraries and add-ons for certain features; React Router is the official routing library
#Installing React Router & Declaring Routes
npm install —save react-router-dom
#Inline Rendering with
Besides the component prop, provides additional ways to render a component. For example, the render prop lets you do inline component rendering.
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
// App components
import Header from './Header';
import Home from './Home';
import About from './About';
import Teachers from './Teachers';
import Courses from './Courses';
const App = () => (
<BrowserRouter>
<div className="container">
<Header />
<Route exact path="/" component={Home} />
<Route path="/about" render={() => <About title="About" />} />
<Route path="/teachers" component={Teachers} />
<Route path="/courses" component={Courses} />
</div>
</BrowserRouter>
);
export default App;
Q. Which component is one of the core components of React Router and keeps your UI in sync with the URL?
<BrowserRouter>
Q. Which <Route>
prop renders a component only when the path matches the URL exactly?
exact
Q. React Router uses JSX syntax to declare routes.
- True. React Router is a set of components, and the declarative syntax of JSX makes it easier to visualize how routes are structured
Q. Which React Router component is responsible for rendering UI (or other components)? - Route
Given this code:
<Route exact path="/signup" component={SignupForm} />
Which of the following is true about Route?
- It renders the SignupForm component only when the URL path is exactly '/signup'
Q. Which <Route>
prop accepts an inline function that gets called when the URL and path match? - render
#Navigating between Routes
Use React Router's <Link>
component to navigate between our routes.
import React from 'react';
import { Link } from 'react-router-dom';
const Header = () => (
<header>
<span className="icn-logo">
<i className="material-icons">code</i>
</span>
<ul className="main-nav">
<li>
<Link exact to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/teachers">Teachers</Link>
</li>
<li>
<Link to="/courses">Courses</Link>
</li>
</ul>
</header>
);
export default Header;
#Styling Active Links
React Router provides a simple way to change the appearance of a link when it's active. The <NavLink>
component is a special version of <Link>
that can recognize when it matches the current URL.
React Router provides an <Redirect>
component that instructs the router to redirect from one route to another.
The match object contains information about how a route is matching the URL. We can access this data from inside components being rendered by <Route>
. e'll use match to dynamically match <Route>
and <NavLink>
to the current URL and path.
import React from 'react';
import { NavLink } from 'react-router-dom';
const Header = () => (
<header>
<span className="icn-logo">
<i className="material-icons">code</i>
</span>
<ul className="main-nav">
<li>
<NavLink exact to="/">Home</NavLink>
</li>
<li>
<NavLink to="/about">About</NavLink>
</li>
<li>
<NavLink to="/teachers">Teachers</NavLink>
</li>
<li>
<NavLink to="/courses">Courses</NavLink>
</li>
</ul>
</header>
);
export default Header;
With React Router, you're able to declare dynamic routes using special URL parameters. The data passed to the URL parameters can be displayed in your app.
- Add a
?
to the end of a parameter - The object can be used to programmatically change the URL.
- Use the npx command to install Create React App and create a new app, all at once. For example:
npx create-react-app my-app
React provides a way to pass data to components without having to pass props manually at every single level, or reach for a state management library like Redux. Context was an experimental feature in older versions of React, and it officially became a stable feature in React 16.3.
- the cascade of props that gets data to parts of the React Component tree
React context API - provide a way to pass data down to components without having to pass props manually at every single level
createContext()
- set up a context and returns an object with a Provider and a Consumer
- Provider
- used as high as possible in the component tree
- allows a Consumer to subscribe to context changes
- Consumer
#Create index.js
inside Context folder
import React from 'react';
const ScoreboardContext = React.createContext();
export const Provider = ScoreboardContext.Provider;
export const Consumer = ScoreboardContext.Consumer;
#import Provider
to App
import {Provider} from './Context';
#Put code of return App into Provider tag
Now that context is set and the provider is in place, we'll provide state to the entire app. We'll set up Consumers that subscribe (or connect) to the Provider component to make use of the context.
#Add value to Provider
<Provider value={this.state.players}>
#Import Consumer to Stats
import {Consumer} from './Context';
#Put code of return into Consumer tag
Render Prop
- a technique for sharing code between React components using a prop whose value is a function
React.Fragment
- group a list of sibling elements or components without having to add an unnecessary reaper element
- Move the
Provider
, along with the state and actions into a separate (higher order) component. As a result, theApp component
will have less code and responsibilities, making it easier to think about and maintain.
Higher-order component (HOC) - a technique for reusing component logic.
- A HOC takes an existing component and returns a new component
children
- a special React prop that lets you pass components as data to other components
- use ES2015 destructuring to extract the state and actions from the value object received from the Provider.
The new core architecture of React 16, codenamed “Fiber,” keeps most of the API intact and backward compatible. You can update existing apps without running into issues. Fiber introduces lots of new, highly anticipated features and improvements to React.
One of the biggest changes in React 16 is how React handles JavaScript errors. It provides a built-in solution for handling errors gracefully, with a new lifecycle method called componentDidCatch().
With componentDidCatch()
comes a new concept of an error boundary. Error boundaries are wrapper components that use componentDidCatch()
to capture errors anywhere in their child component tree and display a fallback UI.
Note: Error boundaries only catch errors in the components below them in the tree. An error boundary can’t catch an error within itself.
React 16 no longer requires that a render method returns a single React element. You can render multiple sibling elements without a wrapping element by returning an array. This eliminates the need for an extra element just to wrap your component tree. The other new return types React 16 supports are strings and numbers.
Updates React v16.2.0 provides a first-class component that can be used in place of arrays. This lets you return multiple children from a component’s render method. Read all about it in the docs. Resources
- New render return types: fragments and strings
- List of supported return types
React 16 introduces a new way of rendering into the DOM. You can render children into a DOM element that exists outside of your App's main DOM tree, with a new feature called “portals.”
React 16 lets you decide if state gets updated via setState to prevent unnecessary re-renders. In your events, you can check if the new value of state is the same as the existing one. If the values are the same, you can return null
and it won’t re-render a component.
constructor() {
super();
this.state = {
gifs: [],
};
}
componentDidMount() {
fetch('http://api.giphy.com/v1/gifs/trending?api_key=dc6zaTOxFJmzC')
.then((response) => response.json())
.then((responseData) => {
this.setState({ gifs: responseData.data });
})
.catch((error) => {
console.log('Error fetching and parsing data', error);
});
}
Resources
- Install axios
npm install --save axios
import axios from 'axios';
componentDidMount() {
axios
.get('http://api.giphy.com/v1/gifs/trending?api_key=dc6zaTOxFJmzC')
.then((response) => {
this.setState({
gifs: response.data.data,
});
})
.catch((error) => {
console.log('Error fetching and parsing data', error);
});
}
Resouce
import React from 'react';
import Gif from './Gif';
const GifList = (props) => {
const results = props.data;
let gifs = results.map((gif) => (
<Gif url={gif.images.fixed_height.url} key={gif.id} />
));
return <ul className="gif-list">{gifs}</ul>;
};
export default GifList;
import React from 'react';
const Gif = (props) => (
<li className="gif-wrap">
<img src={props.url} alt="" />
</li>
);
export default Gif;
performSearch = (query) => {
axios
.get(
`http://api.giphy.com/v1/gifs/search?q=${query}&limit=24&api_key=dc6zaTOxFJmzC`
)
.then((response) => {
this.setState({
gifs: response.data.data,
});
})
.catch((error) => {
console.log('Error fetching and parsing data', error);
});
};
<SearchForm onSearch={this.performSearch} />
handleSubmit = (e) => {
e.preventDefault();
this.props.onSearch(this.state.searchText);
e.currentTarget.reset();
};
#Add loading
constructor() {
super();
this.state = {
gifs: [],
loading: true,
};
}
.then((response) => {
this.setState({
gifs: response.data.data,
loading: false,
});
<div className="main-content">
{this.state.loading ? (
<p>Loading...</p>
) : (
<GifList data={this.state.gifs} />
)}
</div>
#Class components' cons
- Require additional syntax compared to function
- Slower optimization
- Interfere with certain React tools and features
#React Hooks
React Hooks are special built-in functions that allow you to hook into the power of class components, with a cleaner and more straightforward syntax.
- Manage state and rendering of UI when state changes
- Provide access to your app's context
- Update components with an alternative to lifecycle methods
A Hook is a function that lets you "hook into" React state and lifecycle features from function components. The most useful built-in Hook is useState()
, which allows you to do what its name implies: use React state in a function component.
#Set State with useState
- use Hooks inside functions only (Hooks don't work inside classes)
useState()
is the equivalent of boththis.state
andthis.setState
for function components.
import React, { useState } from 'react';
function App() {
const [ score, setScore ] = useState(0); // [0, ƒ]
...
}
useState()
accepts one optional argument – the initial value of the state variable.- Calling
useState()
with the initial state returns an array with two values:- a variable with the current state value
- a function to update that value
- In class components, the state always has to be an object. With
useState()
state can be an object, array, or another JavaScript primitive like a string or integer.
#Update State
- The first time you call useState(), it sets the initial component state
- To update the
score
state of the example App function component, callsetScore()
and pass it the new state
function App() {
const [score, setScore] = useState(0);
return (
<div className="App">
<header className="App-header">
<h1>{ score }</h1>
<button onClick={() => setScore(score + 1)}> // update the score state
Increase score
</button>
</header>
</div>
);
}
#Declare multiple states
- useState() lets you declare one state variable at a time, but you aren’t limited to just one useState() call inside a component. You can call useState() numerous times to declare multiple state variables
import React, { useState } from 'react';
function App() {
const [ score, setScore ] = useState(0);
const [ message, setMessage ] = useState('Welcome!');
}
#Update State Based on Previous State
- If you need to update state using the previous state value, you can pass a function to the method updating state.
return (
<div className="App">
<header className="App-header">
<h1>{ message }</h1>
<h2>{ score }</h2>
<button onClick={() => setScore(prevScore => prevScore + 1)}>
Increase score
</button>
</header>
</div>
);
You've learned that there are different phases in a React component's lifecycle: mounting, updating, and unmounting. React provides lifecycle methods to run code at these specific moments. They are used to re-render a component, update the DOM when data changes, fetch data from an API or perform any necessary cleanup when removing a component. Developers refer to these types of actions as "side effects" because you cannot perform them during rendering (additional code runs after React updates the DOM).
- Common lifecycle methods React uses to handle side effects in class components are
componentDidMount
,componentDidUpdate
, andcomponentWillUnmount
. - Forgetting to include one of these methods when needed, can leave us with stale data or memory leaks.
#Perform Side Effects in Function Components
useEffect
Hook let you perform side effects in function components, and give them access to common lifecycle hooks.
If you’re familiar with React class lifecycle methods, you can think of
useEffect
Hook ascomponentDidMount
,componentDidUpdate
, andcomponentWillUnmount
combined.
useEffect
receives a callback function as the first argument, which is where you perform any side effects
import React, { useState, useEffect } from 'react';
function App() {
const [score, setScore] = useState(0);
const [message] = useState('Welcome!');
// The effect happens after render
useEffect(() => {
console.log('useEffect called!');
});
return (...);
}
- The
useEffect
Hook instructs React to do something after render, so it's called when the component first renders and after each subsequent re-render or update.
#Prevent useEffect from Causing Unnecessary Renders
- The
useEffect
Hook takes an optional array as a second argument that instructs React to skip applying an effect (and re-rendering) if specific values haven’t changed between re-renders. - In the array, you list any dependencies for the effect (states). The array instructs the
useEffect
Hook to run only if one of its dependencies changes. - Passing an empty array as the second argument will run
useEffect
only once after the initial render.
function App() {
const [score, setScore] = useState(0);
const [message] = useState('Welcome!');
useEffect(() => {
console.log('useEffect called!');
}, []); // pass an empty array to run useEffect once
return (...);
}
#Access State Inside useEffect
- You're able to access a state variable (even update state) from inside useEffect
function App() {
const [score, setScore] = useState(0);
const [message] = useState('Welcome!');
useEffect(() => {
document.title = `${message}. Your score is ${score}`;
}, [message, score]);
return (...);
}
Notice how useEffect
uses the score
and message
variables. This means that the variables are now dependencies that need to be listed inside the array. If you do not list score, for example, the title will not display the updated score.
#Data Fetching with useEffect
- You'll most likely use the
useEffect
Hook to fetch data from an API, similar to how you'd use thecomponentDidMount
method in a class.
function App() {
const [data, setData] = useState('');
useEffect(() => {
console.log('useEffect called!');
fetch('https://dog.ceo/api/breeds/image/random')
.then(res => res.json())
.then(data => setData(data.message))
.catch(err => console.log('Oh noes!', err))
}, []);
return (
<div className="App">
<img src={data} alt="A random dog breed" />
</div>
);
}
#"Clean Up" useEffect
-
Some side effects in React require "cleanup," or running additional code when a component unmounts (to prevent a memory leak, for example). With classes, you'd use the
componentWillUnmount()
lifecycle method to perform any necessary cleanup. -
With Hooks, you don't need a separate function to perform cleanup. Returning a function from your effect takes care of the cleanup, running the function when the component unmounts.
#App Component
function App() {
const [data, setData] = useState([]);
const [query, setQuery] = useState('cats');
const [isLoading, setIsLoading] = useState(true);
// update the query state
const performSearch = (value) => setQuery(value);
useEffect(() => {
axios
.get(
`https://api.giphy.com/v1/gifs/search?q=${query}&limit=24&api_key=BG0uinTSDtfym4Q3P2REbOkh7wHDqQz3`
)
.then((response) => setData(response.data.data))
.catch((error) => console.log('Error fetching and parsing data', error))
.finally(() => setIsLoading(false));
}, [query]); // isLoading and data are being updated within the hook (setState), no need to pass them to the dependency array
return (
<div>
<div className="main-header">
<div className="inner">
<h1 className="main-title">GifSearch</h1>
<SearchForm onSearch={performSearch} />
</div>
</div>
<div className="main-content">
{isLoading ? <p>Loading...</p> : <GifList data={data} />}
</div>
</div>
);
}
#SearchForm Component
function SearchForm(props) {
const [searchText, setSearchText] = useState('');
const onSearchChange = (e) => {
setSearchText(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
props.onSearch(searchText);
e.currentTarget.reset();
};
return (
<form className="search-form" onSubmit={handleSubmit}>
<label className="is-hidden" htmlFor="search">
Search
</label>
<input
type="search"
onChange={onSearchChange}
name="search"
placeholder="Search..."
/>
<button type="submit" id="submit" className="search-button">
<i className="material-icons icn-search">search</i>
</button>
</form>
);
}
- React's Context API provides a way to pass data to components without having to pass props manually at every single level (also known as prop-drilling).
- use Context when certain data needs to be accessible to several components at different nesting levels.
- The
useContext
Hook provides the functionality of the Context API in a single function. Once you've created your app's Context, calluseContext()
inside a function component to access any Context state and actions.
#Create Context
import React, { useState } from 'react';
export const ScoreboardContext = React.createContext()
export const Provider = (props) => {
const [players, setPlayers] = useState([]);
return (
<ScoreboardContext.Provider value={{
players,
actions: {
changeScore: handleScoreChange,
}
}}>
{ props.children }
</ScoreboardContext.Provider>
);
};
#useRef
import React, { useContext, useRef } from 'react';
import { ScoreboardContext } from './Context';
const AddPlayerForm = () => {
const { actions } = useContext(ScoreboardContext);
const playerInput = useRef();
return (
<form onSubmit={handleSubmit} >
<input
type="text"
ref={playerInput}
/>
</form>
);
}
#Access Context with useContext
- Acess State & actions
import React, { useContext } from 'react';
import { ScoreboardContext } from './Context';
import Counter from './Counter';
const Player = ({ index }) => {
const { players, actions } = useContext(ScoreboardContext);
return (
<div className="player">
<span className="player-name">
<button
className="remove-player"
onClick={() => actions.removePlayer(players[index].id)}>✖
</button>
{ players[index].name }
</span>
<Counter index={index} />
</div>
);
};
useReducer
can help when dealing with complex state logic or when the next state depends on the previous state.useRef
provides an easier way to access DOM nodes or React elements created in the render method with a ref attribute.useHistory
Hook is imported from React Router Dom and provides access to the history object.
#Custom Hooks
With custom Hooks, you can reuse logic easily, share information across components and write less code. Like built-in Hooks, custom Hooks are JavaScript functions whose names start with use
#Rules of Hooks There are two main rules you should follow when using Hooks:
- Call Hooks only at the top level of your React function. For example, don't call Hooks inside loops, conditions, or nested functions.
- Call Hooks from React function components only. Hooks do not work inside class components.
React provides a handy ESLint plugin called eslint-plugin-react-hooks to help enforce these rules.
npm run build
npm install -g serve
serve -s build
Learn how to deploy and host a React app on GitHub Pages, a free hosting solution provided by GitHub that lets others view your repository as a static website.
#Step1. Add homepage to package.json
"homepage": "https://alan-nguyen.github.io/scoreboard",
#Step 2. Install Github pages
npm install --save gh-pages
#Step 3. Setup scripts in package.json
"predeploy": "npm runj jj
build",
"deploy": "gh-pages -d build",
#Step 4. Publish to build to Github pages
npm run deploy
Set a Base URL
- When using React Router, if your app is served from a sub-directory, pass the
'basename'
prop to the router to set the base URL for all locations. For example:
<BrowserRouter basename="/course-directory">
#S1 - Install Now
npm install -g now
#S2 - create now.json file
{
"version": 2,
"name": "app-name",
"builds": [
{ "src": "package.json", "use": "@now/static-build" }
],
"routes": [
{"src": "^/static/(.*)", "dest": "/static/$1"},
{"src": "^/favicon.ico", "dest": "/favicon.ico"},
{"src": "^/asset-manifest.json", "dest": "/asset-manifest.json"},
{"src": "^/manifest.json", "dest": "/manifest.json"},
{"src": "^/service-worker.js", "headers": {"cache-control": "s-maxage=0"}, "dest": "/service-worker.js"},
{"src": "^/precache-manifest.(.*)", "dest": "/precache-manifest.$1"},
{"src": "^/(.*)", "dest": "/index.html"}
]
}
#S3 - Set up package.json script
"scripts": {
...
"now-build": "react-scripts build && mv build dist"
}
#S4 - Deploy
now
Simple way - drop build folder to Netlify
#Command line
- Install Netlify cli
npm install netlify-cli -g
#Deploy project
netlify deploy
deploy path build
#Add _redirects file inside build folder
- Include rewrite rule
/* /index.html 200
The following courses will help you practice building React apps, and guide you through the basics of Redux, a JavaScript library for managing application state.
Learn React programming patterns by building an application for keeping track of RSVP's.
Learn how to implement the Basic Authentication scheme in a React application using an Express REST API.
Redux is a state management framework that provides a robust infrastructure that complements React applications.
https://teamtreehouse.com/library/introducing-create-react-native-app
#What is Basic Authentication?
#Set up the React App
#Run the Express Server
#Set up User Registration
#Implement the Sign up Form
#Set up Basic Authentication
#Implement Sign In
#Display Authenticated User in the Header
#Protect Routes that Require Authentication
#Implement User Sign Out
#Refine and Complete Authentication
#Preserve the User State with Cookies