Tecnate | Last Updated: 2024.05.01 |
This document is a brain dump for things that I’ve picked up about the React library. Use at your own risk!
React is a JavaScript library used to build user interfaces by implementing modular code that can be reused throughout your application.
Here are the fundamental concepts you’ll need to build/maintain React apps:
- ❌ Don't use class components (deprecated).
- ✅ Use functional components.
- State management is decoupled with function components (cleaner setup/inheritance).
- Libraries use hooks; classes won't be compatible.
Text, numbers, arrays render as text.
<p>[123] vs {[456]}</p>
// [123] vs 456
Objects return an error if rendered.
<p></p>
// Error
Booleans don’t render.
<p>{true === true}</p>
// (renders nothing)
Variable render their values.
const name = "Clark";
<p>{name}</p>; // Clark.
Syntax Note:
{}
vs{ {} }
: The outer pair of{}
indicates a JSX expression, while an inner pair{ {} }
contains an object within the expression.
Inputs in React forms. Here is a basic example of a controlled input for a form which has search
and setSearch
being passed to the Component as props.
<form className="searchForm" onSubmit={(e) => e.preventDefault()}>
<label htmlFor="search">Search Posts</label>
<input
id="search"
type="text"
placeholder="Search Posts"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
</form>
Use the Create React App toolchain to spin up a React application quickly using Node.js, npm, and npx.
node -v
npm -v
npx -v
npx create-react-app project-name
.cd project-name
npm run start
For simple projects, you can delete the following files:
Open up the following files to delete unnecessary code blocks:
import reportWebVitals from './reportWebVitals';
reportWebVitals();
Uninstall any unused dependencies from your package.json file:
npm uninstall @testing-library/jest-dom @testing-library/react @testing-library/user-event web-vitals
React requires several things to work properly. Here are the JavaScript tasks that need to be addressed with their respective tools:
In your terminal, create the root directory for your project before initializing NPM.
# Make your project's root directory
mkdir path/to/directory/myProject
# Navigate into your project root
cd path/to/directory/myProject
# Initialize Node Package Manager
npm init
# You should see a prompt for with the name of your project.
# Hit 'Enter/Return' for all prompts.
# "Is this ok?"
yes
There are two types of packages you need to install:
- dependencies: packages imported by our application.
- devDependencies packages required for development and testing.
# Install React
npm install --save react
# Install React-DOM
npm install --save react-dom
# Install Babel & Webpack
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader webpack webpack-cli webpack-dev-server html-webpack-plugin
# Install URL Loader & File Loader
# For image rendering on a local server
npm install --save-dev url-loader file-loader
# Install CSS/Style Loader
npm install --save-dev style-loader css-loader
Add the following templates into the root of your project:
template
and entry
filepaths to your root index.html and index.js are correct!Open your package.json file and update your scripts like so:
"scripts": {
"start": "webpack-dev-server --mode development --open --hot"
},
This will enable you to execute the webpack-dev-server and allow for live reloading of changes in your default web browser.
That should be it for installation!
Run npm run start
to execute the script which starts React and allows you to view your project in the browser. You should see a message similar to this in your terminal:
Project is running at:
Loopback: http://localhost:8080/
Open a second terminal window for any development needs and allow Node to run in the background in the first window. Press Ctrl+C
in the terminal to stop the webpack-dev-server at any time.
# Navigate to your project directory
cd project-name
# Navigate to the GitHub repo
# Click the green Code button
# SSH: copy repo location
# Clone the repo in terminal
git clone git@github...
# Rename origin to upstream
git remote rename origin upstream
Renaming the origin allows you to have a connection to the codebase while leaving the origin connection free if you decide to create your own repo later.
After you have installed React, preferably with the Create React App (Installation Option A above), you can start/resume development anytime following these general steps:
Open 3 integrated terminal tabs on your root directory. Keep all 3 running in the background during your development work:
Terminal 1: runs your server environment, e.g. json-server:
npx json-server -p 3500 -w data/db.json
-p
: port-w
: watch for changes (i.e. database)Terminal 2: executes your React start script, opens your app in the browser, and watches for changes:
npm run start
Terminal 3: general purpose terminal for any development work and Git tracking:
git status
.git checkout development
.git add . && git commit -m "Comment goes here"
.git status
.git add . && git commit -m "Comment goes here"
.git push
.git checkout main
.git status
.git merge development
.git push
.Ctrl+C
in each terminal.# List the React installed versions and dependencies
npm list react
# Uninstall React:
npm uninstall react
# Uninstall ReactDOM
npm uninstall react-dom
# Delete the package files
rm package.json package-lock.json
There are several ways you can define layouts for your React App (CSS stylesheets, Bootstrap, React Grid System, etc). Before committing to any framework, determine how your UI can be divided into rows and columns.
Be careful if you choose to use Bootstrap; it contains JavaScript that may conflict with React.
# Install React Grid
npm install --save react-grid-system
Once installed, add the following to your components:
import { Container, Row, Col } from "react-grid-system";
const withAuth = (Component)...
The village metaphor is a useful way to conceptualize modules in React as the user interface, made up of hierarchical files and functionality that are imported and exported throughout the app.
Using a village as a framework for structure, here’s one way to organize directories & files:
Lifecycle Methods: functions added to a class component and called at specific moments during the life of said component.
There are three phases to a React components, which you can think of as the birth, life, and death of a component:
For example, to save data between sessions:
// 1. Save state to the browser's storage.
componentDidUpdate() {
const stateString = JSON.stringify(this.state);
localStorage.setItem("stateString", stateString);
}
// 2. Fetch data when UI is reopened.
componentDidMount() {
const stateString = localStorage.getItem("stateString");
// 3. Set state to the previous session's value.
if (stateString) {
const savedState = JSON.parse(stateString);
this.setState(savedState);
}
}
Components are defined where exported and used where imported.
Props are defined once, at the highest view (often but not necessarily where the Component is used). But they need to be made available down the entire Component hierarchy; they are passed down every nested file until they are used where the Component is defined.
For an example Title component, if your nested directories were: Page/Header/Title, your component/props would look like the following:
// Page.js
import Header from "./Page/Header"
class Page extends React.Component {
render() {
// Defines title prop
return <Header title="Hello, World!"/>;
}
}
export default Page;
// Page.js/Header.js
import Title from "./Page/Header/Title"
class Header extends React.Component {
render() {
// Uses Title component & passes title prop
return <Title title={this.props.title}/>;
/* You could define the prop here if you didn't want to define it in the Header, but this would make your Title less flexible:
return <Title title="Hello, World!"/>; */
}
}
export default Header;
// Page.js/Header.js/Title.js
class Title extends React.Component {
render() {
// Uses title prop
return <h1 className="blue">{this.props.title}</h1>;
}
}
export default Title;
createContext
hook instead.)createContext
hook to wrap your entire app (or specific parts of it) within a data context that provides values to your components.
Source: “Skillcrush - Introduction to JavaScript React - Module 11.2”
There are several phases of a greenfield project that you should complete in the following order: dividing the UI into its disparate components, coding a static version of the UI, organizing the data flow, and adding interactivity.
Source: “Skillcrush - Introduction to JavaScript React - Module 12.3”
useState
: manages state within a functional component; declare a state variable and a function to update said variable.
useEffect
: perform side effects in a component after the component has rendered.
// Every rerender
useEffect(() => {
// Functions inside this hook run AFTER functions outside this hook;
// i.e. your page components will mount before this inner function is called.
console.log("Runs every time component rerenders, e.g. onChange");
});
// onMount
useEffect(() => {
console.log("Runs once)");
}, []);
// Condition based
useEffect(() => {
console.log("Runs when dependency changes");
}, [dependency]);
// Condition based clean up
useEffect(() => {
console.log("Runs when dependency changes");
return () => {
console.log("Use a return to clean up--this runs before the actual code");
};
}, [dependency]);
Use npx to run JSON Server without installing it as a dependency in your project:
npx json-server -p 3500 -w data/db.json
-p
: port-w
: watchInstall Axios as a dependency
npm i axios
Set up Axios in desired file, e.g. src/api/posts.js
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:3500",
});
In the container component (e.g. App), set up the useEffect logic.
import api from "./api/posts";
function App() {
useEffect(() => {
const fetchPosts = async () => {
try {
const response = await api.get("/posts");
setPosts(response.data);
} catch (err) {
if (err.response) {
// Not in HTTP 200 response range
console.log(err.response.data);
console.log(err.response.status);
console.log(err.response.headers);
} else {
console.log(`Error: ${err.message}`);
}
}
};
fetchPosts();
}, []);
}