Author: Kevin Chhay
- Installation
- Introduction
- Introducing JSX
- Function Component and Props
- Composition
- Handling Events
- State Hook
- Forms
- Lists
- Conditional Rendering
- Dynamically-Computed Styles
https://reactjs.org/docs/getting-started.html
https://reactjs.org/docs/hello-world.html
Hello World
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<h1>Hello, world!</h1>);
https://reactjs.org/docs/introducing-jsx.html
https://reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx
const name = "Josh Perez";
const element = <h1>Hello, {name}</h1>;
https://reactjs.org/docs/components-and-props.html#function-and-class-components
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Alternative:
const Welcome = (props) => {
return <h1>Hello, {props.name}</h1>;
}
Export:
const Welcome = (props) => {
return <h1>Hello, {props.name}</h1>;
}
export default Welcome;
Import:
import Welcome from "./components/Welcome";
const App = () => {
return (
<div>
<Welcome />
</div>
);
}
// Child Component
const Child = (props) => {
const clickHandler = () => {
props.onGetMessage("Hello World");
}
return <button onClick={clickHandler}>Click Me</button>;
}
// Parent Component
import Child from "./components/child";
const Parent = () => {
const getMessageHandler = (message) => {
console.log(message);
}
return (
<div>
<Child onGetMessage={getMessageHandler} />
</div>
);
}
https://reactjs.org/docs/composition-vs-inheritance.html
Use the special children prop to pass children
elements directly into their output:
function FancyBorder(props) {
return (
<div className={"FancyBorder FancyBorder-" + props.color}>
{props.children}
</div>
);
}
This lets other components pass arbitrary children to them by nesting the JSX:
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">Welcome</h1>
<p className="Dialog-message">Thank you for visiting our spacecraft!</p>
</FancyBorder>
);
}
https://reactjs.org/docs/handling-events.html
const Component = () => {
const clickHander = () => {
console.log("Clicked!");
}
return <button onClick={clickHandler}>Click Me</button>;
}
https://reactjs.org/docs/hooks-state.html
import React, { useState } from "react";
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
Multiple State:
import React, { useState } from "react";
const Component = () => {
const [userInput, setUserInput] = useState({
enteredTitle: "",
enteredAmount: "",
enteredDate: ""
});
const titleChangeHandler = (event) => {
setUserInput((prevState) => {
return {
...prevState,
enteredTitle: event.target.value
};
});
}
return (
// ...
);
}
https://reactjs.org/docs/forms.html
import React, { useState } from "react";
const Component = () => {
const [name, setName] = useState("");
const nameChangeHandler = (event) => {
setName(event.target.value);
}
const submitHandler = (event) => {
event.preventDefault();
}
return (
<form onSubmit={submitHandler}>
<div>Name: {name}</div>
<input type="text" value={name} onChange={nameChangeHandler} />
</form>
);
}
https://reactjs.org/docs/lists-and-keys.html
Embedding map() in JSX:
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
}
https://reactjs.org/docs/conditional-rendering.html
Logical && Operator
const Component = () => {
return (
<div>
{false && "Hello World"}
{true && "Greetings"}
</div>
);
}
Conditional (Ternary) Operator
const Component = () => {
const isLoggedIn = true;
return <div>{isLoggedIn ? "Logged in" : "Not logged in"}</div>;
}
https://reactjs.org/docs/dom-elements.html#style
className
should be used to reference classes defined in an external CSS stylesheet. style is most often used in React applications to add dynamically-computed styles at render time.
Inline Style
const Component = () => {
let textColor = "alert";
textColor = "alert" ? "red" : "green";
return <div style={{color: textColor}}>Hello World</div>;
}
Dynamic Class
const Component = () => {
const textColor = "alert"
return (
<div className={`form-control ${textColor === "alert" && "text-danger"}`}>
Hello World
</div>
);
}
https://reactjs.org/docs/fragments.html
Short Syntax
const Component = () => {
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
}
https://reactjs.org/docs/portals.html
<!-- index.html -->
<html>
<body>
<div id="app-root"></div>
<div id="modal-root"></div>
</body>
</html>
// Component.js
import ReactDOM from "react-dom";
import Modal from "./components/modal";
const Component = () => {
return (
<div>
{ReactDOM.createPortal(<Modal />, document.getElementById("modal-root"))}
</div>
);
}
https://reactjs.org/docs/refs-and-the-dom.html
refs
to access the form values from the DOM is considered an uncontrolled compoment. It is recommended to use controlled components.
import React, { useRef } from "react";
const Component = () => {
const nameInputRef = useRef();
const clickHandler = () => {
console.log(nameInputRef.current.value);
}
return (
<div>
<input type="text" ref={nameInputRef} />
<button onClick={clickHandler} />
</div>
);
}
https://reactjs.org/docs/hooks-effect.html
([])
as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run.
Without Dependencies (empty array)
import React, { useState, useEffect } from "react";
const Component = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
if (localStorage.getItem("isLoggedIn") === "1") {
setIsLoggedIn(true);
}
}, []);
return <div>{isLoggedIn ? "Logged in" : "Not logged in"}</div>;
}
With Dependencies
import React, { useState, useEffect } from "react";
const Component = () => {
const [emailInput, setEmailInput] = useState("");
const [passwordInput, setPasswordInput] = useState("");
const [isFormValid, setIsFormValid] = useState(false);
const emailChangeHandler = (event) => {
setEmailInput(event.target.value);
}
const passwordChangeHandler = (event) => {
setPasswordInput(event.target.value);
}
useEffect(() => {
// Debounce
const id = setTimeout(() => {
setIsFormValid(emailInput.includes("@"));
}, 500);
// Clean up function (runs before the effect)
return () => {
clearTimeout(id);
};
}, [emailInput]); // Only re-run the effect if emailInput changes
return (
<form>
<p>{!isFormValid && "Enter a valid email."}</p>
<input type="text" value={emailInput} onChange={emailChangeHandler} />
<input type="text" value={passwordInput} onChange={passwordChangeHandler} />
</form>
);
}
https://reactjs.org/docs/hooks-reference.html#usereducer
import React, { useReducer } from "react";
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 Counter = () => {
const [state, dispatch] = useReducer(reducer, {count: 0});
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
https://reactjs.org/docs/context.html
// store/auth-context.js
import React from "react"
// Passing an object into createContext method is optional. It's just for better auto-completion in the IDE.
const AuthContext = React.createContext({
isLoggedIn: false,
onLogout: () => {}
});
export default AuthContext;
// Parent
// App.js
import React, { useState } from "react";
import Login from "./components/Login/Login";
import Home from "./components/Home/Home";
import MainHeader from "./components/MainHeader/MainHeader";
import AuthContext from "./store/auth-context";
const App = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const loginHandler = () => {
// do stuff
};
const logoutHandler = () => {
// do stuff
};
return (
<AuthContext.Provider
value={{
isLoggedIn: isLoggedIn,
onLogout: logoutHandler
}}
>
<MainHeader />
<main>
{!isLoggedIn && <Login onLogin={loginHandler} />}
{isLoggedIn && <Home onLogout={logoutHandler} />}
</main>
</AuthContext.Provider>
);
}
export default App;
// Child
// components/MainHeader.js
import React from 'react';
import Navigation from './Navigation';
const MainHeader = () => {
return (
<header className={classes['main-header']}>
<h1>A Typical Page</h1>
<Navigation />
</header>
);
};
export default MainHeader;
// Grandchild
// components/Navigation.js
import React, { useContext } from "react";
import AuthContext from "../../store/auth-context";
const Navigation = () => {
const ctx = useContext(AuthContext);
return (
<nav>
<ul>
{ctx.isLoggedIn && (
<li>
<a href="/">Users</a>
</li>
)}
{ctx.isLoggedIn && (
<li>
<a href="/">Admin</a>
</li>
)}
{ctx.isLoggedIn && (
<li>
<button onClick={ctx.onLogout}>Logout</button>
</li>
)}
</ul>
</nav>
);
}
export default Navigation;