React.js 已成為現代 Web 開發的基石,用於建立動態和高效能 Web 應用程式。這份全面的備忘單將涵蓋您掌握 React.js 所需了解的所有內容,包括實際範例、程式碼片段以及所有功能的詳細說明。目標是提供可供您隨時參考的深入指南。
反應簡介
開始使用 React
設定環境
建立一個新的 React 應用程式
功能元件
類別元件
功能元件和類別元件之間的差異
JSX 語法
嵌入表達式
JSX 屬性
了解狀態
使用 useState Hook 管理狀態
了解道具
傳遞道具
道具類型和預設道具
類別元件中的生命週期方法
使用 useEffect 鉤子
使用 useEffect 進行清理
React 中的事件處理
綜合事件
處理表格
事件處理程序最佳實踐
if-else 語句
三元運算符
邏輯 && 運算符
內嵌 If 與邏輯 && 運算符
渲染列表
使用按鍵
鍵只能在兄弟姊妹中是唯一的
- Handling Form Data
- Controlled vs Uncontrolled Components
- Using Refs for Uncontrolled Components
- Form Validation
- Setting Up React Router
- Route Parameters
- Nested Routes
- Redirects and Navigation
- Creating Context
- Consuming Context
- Context with Functional Components
- Updating Context
- Context Best Practices
- Basic Hooks (useState, useEffect)
- Additional Hooks (useContext, useReducer)
- Custom Hooks
- Rules of Hooks
- Understanding HOCs
- Creating HOCs
- Using HOCs
- HOC Best Practices
- Implementing Error Boundaries
- Catching Errors
- Error Boundaries Best Practices
- Memoization
- Code Splitting
- Lazy Loading
- React Profiler
- Unit Testing with Jest
- Component Testing with React Testing Library
- End-to-End Testing with Cypress
- Testing Best Practices
React.js 通常簡稱為 React,是一個開源 JavaScript 函式庫,用於建立使用者介面,特別是對於需要快速互動式使用者體驗的單頁應用程式。 React 由 Facebook 開發,允許開發人員建立大型 Web 應用程式,這些應用程式可以有效地更新和渲染以回應資料變更。
React 的核心概念是元件,它是一個獨立的模組,可以呈現一些輸出。元件可以獨立嵌套、管理和處理,使開發過程高效且可維護。
在開始使用React之前,您需要設定開發環境。就是這樣:
從官方網站下載並安裝 Node.js。
透過執行以下命令驗證安裝:
node -v
npm -v
npm install -g create-react-app
一旦環境設定完畢,您就可以建立一個新的 React 應用程式。
npx create-react-app my-app
cd my-app
npm start
此命令建立一個具有指定名稱( my-app
)的新目錄,設定一個新的 React 專案,並啟動開發伺服器。您可以開啟瀏覽器並造訪http://localhost:3000
來查看新的 React 應用程式。
元件是任何 React 應用程式的建置塊。它們讓您可以將 UI 分成獨立的、可重複使用的部分。
函數式元件是接受 props 作為參數並傳回 React 元素的 JavaScript 函數。它們比類別元件更簡單、更容易編寫。
import React from 'react';
const Welcome = ({ name }) => {
return <h1>Welcome, {name}!</h1>;
};
export default Welcome;
類別元件是擴展React.Component
的 ES6 類,並具有傳回 React 元素的 render 方法。
import React, { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>Welcome, {this.props.name}!</h1>;
}
}
export default Welcome;
狀態管理:功能元件使用鉤子( useState
、 useEffect
等)進行狀態管理,而類別元件則使用this.state
和生命週期方法。
生命週期方法:類別元件具有生命週期方法,例如componentDidMount
、 componentDidUpdate
和componentWillUnmount
。功能元件使用useEffect
鉤子來處理副作用。
簡單性:函數式元件更簡單、更簡潔,使它們更易於閱讀和維護。
JSX 是一種語法擴展,可讓您直接在 JavaScript 中編寫 HTML。它產生 React“元素”。
JSX 看起來像 HTML,但被轉換為 JavaScript。
const element = <h1>Hello, world!</h1>;
您可以透過將任何 JavaScript 表達式括在大括號中來將其嵌入到 JSX 中。
const name = 'John';
const element = <h1>Hello, {name}!</h1>;
JSX 允許您使用類似 HTML 的語法的屬性。
const element = <img src={user.avatarUrl} alt={user.name} />;
State 是一個內建物件,用來儲存屬於元件的屬性值。當狀態物件發生變化時,元件會重新渲染。
useState
鉤子用於向功能元件加入狀態。
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
};
export default Counter;
Props 是傳遞給 React 元件的參數。 Props 透過 HTML 屬性傳遞給元件。
道具是唯讀且不可變的。
const Greeting = (props) => {
return <h1>Hello, {props.name}!</h1>;
};
const App = () => {
return <Greeting name="Alice" />;
};
PropTypes 可讓您定義元件應接收的 props 類型。可以定義預設 props 以確保 prop 在未指定的情況下具有值。
import React from 'react';
import PropTypes from 'prop-types';
const Greeting = ({ name }) => {
return <h1>Hello, {name}!</h1>;
};
Greeting.propTypes = {
name: PropTypes.string.isRequired,
};
Greeting.defaultProps = {
name: 'Guest',
};
export default Greeting;
生命週期方法是類別元件中的特殊方法,它們在元件生命週期的特定點執行。
componentDidMount :在元件渲染後執行。
componentDidUpdate :在元件的更新刷新到 DOM 後執行。
componentWillUnmount :在元件從 DOM 中刪除之前執行。
class MyComponent extends React.Component {
componentDidMount() {
// Runs after component is mounted
}
componentDidUpdate(prevProps, prevState) {
// Runs after component updates
}
componentWillUnmount() {
// Runs before component is unmounted
}
render() {
return <div>My Component</div>;
}
}
useEffect
掛鉤結合了componentDidMount
、 componentDidUpdate
和componentWillUnmount
的功能。
import React, { useState, useEffect } from 'react';
const MyComponent = () => {
const [count, setCount] = useState(0);
useEffect(() => {
// Runs on mount and update
document.title = `You clicked ${count} times`;
// Cleanup function (runs on unmount)
return () => {
console.log('Cleanup');
};
}, [count]); // Dependency array
return (
<div>
<p>You
clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
};
export default MyComponent;
React 事件使用駝峰式命名,而不是小寫。使用 JSX,您可以傳遞一個函數作為事件處理程序,而不是一個字串。
const handleClick = () => {
console.log('Button clicked');
};
const MyComponent = () => {
return <button onClick={handleClick}>Click me</button>;
};
React 的事件系統稱為綜合事件。它是瀏覽器本機事件系統的跨瀏覽器包裝器。
在 React 中處理表單涉及控制輸入元素和管理狀態。
import React, { useState } from 'react';
const MyForm = () => {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
alert('A name was submitted: ' + value);
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={value} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
};
export default MyForm;
避免內聯事件處理程序:在 JSX 外部定義事件處理程序,以獲得更好的可讀性和效能。
使用箭頭函數:使用箭頭函數可以避免this
綁定出現問題。
去抖昂貴的操作:去抖昂貴的操作(如 API 呼叫)以避免效能問題。
您可以在render
方法中使用 JavaScript if-else 語句。
const MyComponent = ({ isLoggedIn }) => {
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
} else {
return <h1>Please sign in.</h1>;
}
};
三元運算子是執行條件渲染的簡潔方法。
const MyComponent = ({ isLoggedIn }) => {
return (
<div>
{isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign in.</h1>}
</div>
);
};
您可以使用邏輯 && 運算子有條件地包含元素。
const MyComponent = ({ isLoggedIn }) => {
return (
<div>
{isLoggedIn && <h1>Welcome back!</h1>}
</div>
);
};
帶有邏輯 && 運算子的內聯 if 允許您有條件地在輸出中包含元素。
const Mailbox = ({ unreadMessages }) => {
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
};
您可以建立元素集合並使用大括號{}
將它們包含在 JSX 中。
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
const NumberList = () => {
return (
<ul>{listItems}</ul>
);
};
鍵可協助 React 辨識哪些專案已變更、新增或刪除。應為陣列內的元素提供鍵,以便為元素提供穩定的標識。
const NumberList = (props) => {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
};
陣列中使用的鍵在其兄弟陣列中應該是唯一的。
function Blog(props) {
const sidebar = (
<ul>
{props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
const content = props.posts.map((post) =>
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
);
return (
<div>
{sidebar}
<hr />
{content}
</div>
);
}
在 React 中處理表單資料涉及管理表單欄位的狀態。
import React, { useState } from 'react';
const MyForm = () => {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
alert('A name was submitted: ' + value);
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={value} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
};
export default MyForm;
受控元件是由 React 狀態控制的元件。不受控制的元件是那些維持其自身內部狀態的元件。
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Refs 提供了一種存取 DOM 節點或在 render 方法中建立的 React 元素的方法。
class NameForm extends React.Component {
constructor(props) {
super(props);
this.input = React.createRef();
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
表單驗證可確保使用者輸入有效。
const MyForm = () => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [error, setError] = useState('');
const handleSubmit = (event) => {
event.preventDefault();
if (!name || !email) {
setError('Name and Email are required');
} else {
setError('');
// Submit form
}
};
return (
<form onSubmit={handleSubmit}>
{error && <p>{error}</p>}
<label>
Name:
<input type="text" value={name} onChange={(e) => setName(e.target.value)} />
</label>
<label>
Email:
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
</label>
<input type="submit" value="Submit" />
</form>
);
};
export default MyForm;
React Router 是一個用於在 React 應用程式中進行路由的函式庫。它允許您根據 URL 處理不同元件的導航和渲染。
npm install react-router-dom
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
const Home = () => <h2>Home</h2>;
const About = () => <h2>About</h2>;
const App = () => {
return (
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</Router>
);
};
export default App;
您可以使用路由參數從 URL 擷取值。
import React from 'react';
import { BrowserRouter as Router, Route,
Switch, useParams } from 'react-router-dom';
const User = () => {
const { id } = useParams();
return <h2>User ID: {id}</h2>;
};
const App = () => {
return (
<Router>
<Switch>
<Route path="/user/:id" component={User} />
</Switch>
</Router>
);
};
export default App;
嵌套路由可讓您在父元件內渲染子元件。
import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link, useRouteMatch } from 'react-router-dom';
const Topic = ({ match }) => <h3>Requested Topic ID: {match.params.topicId}</h3>;
const Topics = ({ match }) => {
let { path, url } = useRouteMatch();
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${url}/components`}>Components</Link>
</li>
<li>
<Link to={`${url}/props-v-state`}>Props v. State</Link>
</li>
</ul>
<Switch>
<Route exact path={path}>
<h3>Please select a topic.</h3>
</Route>
<Route path={`${path}/:topicId`} component={Topic} />
</Switch>
</div>
);
};
const App = () => {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/topics" component={Topics} />
</Switch>
</div>
</Router>
);
};
export default App;
您可以使用Redirect
元件以程式設計方式重定向到不同的路由。
import React from 'react';
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
const Home = () => <h2>Home</h2>;
const About = () => <h2>About</h2>;
const App = () => {
return (
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Redirect from="/old-path" to="/new-path" />
</Switch>
</Router>
);
};
export default App;
Context API 提供了一種透過元件樹傳遞資料的方法,而無需在每個層級手動向下傳遞 props。
若要建立上下文,請使用React.createContext
。
const MyContext = React.createContext();
若要使用上下文值,請在功能元件中使用useContext
掛鉤,或在類別元件中使用Context.Consumer
。
const MyComponent = () => {
const value = useContext(MyContext);
return <div>{value}</div>;
};
const MyComponent = () => {
return (
<MyContext.Provider value="Hello">
<AnotherComponent />
</MyContext.Provider>
);
};
const AnotherComponent = () => {
const value = useContext(MyContext);
return <div>{value}</div>;
};
若要更新上下文,請建立一個具有狀態的提供者元件。
const MyProvider = ({ children }) => {
const [value, setValue] = useState('Hello');
return (
<MyContext.Provider value={{ value, setValue }}>
{children}
</MyContext.Provider>
);
};
const MyComponent = () => {
const { value, setValue } = useContext(MyContext);
return (
<div>
{value}
<button onClick={() => setValue('Updated Value')}>Update</button>
</div>
);
};
避免過度使用上下文:謹慎使用上下文,並且僅針對全域資料。
使用多個上下文:透過使用多個上下文來分離關注點。
記憶上下文值:使用useMemo
來避免不必要的重新渲染。
Hooks 是允許您在功能元件中使用狀態和其他 React 功能的函數。
useState :向功能元件新增狀態。
useEffect :在功能元件中執行副作用。
useContext :存取上下文值。
useReducer :管理複雜的狀態邏輯。
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();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}
自訂鉤子是封裝邏輯的函數,可以跨元件重複使用。
const useFetch = (url) => {
const [data, setData] = useState(null);
useEffect(() => {
fetch(url)
.then((response) => response.json())
.then((data) => setData(data));
}, [url]);
return data;
};
const MyComponent = () => {
const data = useFetch('https://api.example.com/data');
return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
};
在頂層呼叫鉤子:不要在循環、條件或巢狀函數內呼叫鉤子。
僅從 React 函數呼叫鉤子:從功能元件或自訂鉤子呼叫鉤子。
高階元件 (HOC) 是獲取元件並傳回新元件的函數。
HOC 用於為元件新增附加功能。
const withLogging = (WrappedComponent) => {
return (props) => {
console.log('Rendering', WrappedComponent.name);
return <WrappedComponent {...props} />;
};
};
const EnhancedComponent = withLogging(MyComponent);
const MyComponent = (props) => {
return <div>My Component</div>;
};
const EnhancedComponent = withLogging(MyComponent);
不要改變原始元件:傳回一個新元件。
使用顯示名稱進行偵錯:在 HOC 上設定displayName
以便更好地進行偵錯。
錯誤邊界是 React 元件,它可以在其子元件樹中的任何位置捕獲 JavaScript 錯誤、記錄這些錯誤並顯示後備 UI。
錯誤邊界會在渲染期間、生命週期方法以及其下方的整個樹的構造函數中捕獲錯誤。
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.log(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
錯誤邊界捕捉渲染方法和生命週期方法中的錯誤。
const MyComponent = () => {
throw new Error('An error occurred');
return <div>My Component</div>;
};
const App = () => {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
};
使用錯誤邊界捕獲元件中的錯誤:使用錯誤邊界捕獲並顯示 UI 元件中的錯誤。
記錄錯誤以進行偵錯:將錯誤記錄到外部服務以進行偵錯。
記憶化有助於避免不必要的重新渲染元件。
import React, { memo } from 'react';
const MyComponent = memo(({ value }) => {
return <div>{value}</div>;
});
程式碼分割有助於僅載入必要的程式碼並提高效能。
import React, { Suspense, lazy } from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));
const MyComponent = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
);
};
延遲載入有助於僅在需要時載入元件。
import React, { Suspense, lazy } from 'react';
const Other
Component = lazy(() => import('./OtherComponent'));
const MyComponent = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
);
};
useMemo :記住昂貴的計算。
useCallback :記憶函數。
const MyComponent = ({ value }) => {
const memoizedValue = useMemo(() => {
return computeExpensiveValue(value);
}, [value]);
const memoizedCallback = useCallback(() => {
doSomething(value);
}, [value]);
return (
<div>
{memoizedValue}
<button onClick={memoizedCallback}>Click me</button>
</div>
);
};
使用 React Developer Tools 來辨識效能瓶頸。
Jest 和 React 測試庫是測試 React 元件的熱門工具。
快照測試:捕獲渲染的元件並將其與已儲存的快照進行比較。
單元測試:測試各個元件和功能。
整合測試:測試元件和服務之間的整合。
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
test('renders MyComponent', () => {
render(<MyComponent />);
const element = screen.getByText(/My Component/i);
expect(element).toBeInTheDocument();
});
依功能組織元件:將相關元件分組在一起。
使用描述性名稱:為元件和道具使用清晰且描述性的名稱。
保持元件較小:將大型元件分解為較小的、可重複使用的元件。
Lift state up :將狀態提升到最近的共同祖先。
使用 Context 進行全域狀態:使用 Context API 進行全域狀態管理。
使用 CSS 模組:將 CSS 模組用於範圍化和模組化樣式。
使用樣式元件:使用樣式元件進行動態樣式設定。
避免不必要的重新渲染:使用記憶和 React 的內建效能最佳化工具。
使用程式碼拆分:拆分程式碼以僅加載必要的元件。
編寫全面的測試:為應用程式的所有關鍵部分編寫測試。
使用快照測試:使用快照測試來擷取意外的變更。
React.js 是一個用於建立現代 Web 應用程式的強大函式庫。透過理解和利用其核心概念,您可以建立高效、可維護和可擴展的應用程式。這份備忘錄是幫助您掌握 React.js 的綜合指南,涵蓋從基本概念到高階主題的所有內容。
原文出處:https://dev.to/raajaryan/comprehensive-reactjs-cheatsheet-for-developers-17e4