React.js 已成为现代 Web 开发中构建动态和高性能 Web 应用程序的基石。这份全面的备忘单将涵盖您掌握 React.js 所需了解的所有内容,包括实际示例、代码片段以及所有功能的详细说明。我们的目标是提供您可以随时参考的深入指南。
React.js,通常简称为 React,是一个开源 JavaScript 库,用于构建用户界面,特别是对于需要快速、交互式用户体验的单页应用程序。 React 由 Facebook 开发,允许开发人员创建大型 Web 应用程序,这些应用程序可以有效地更新和渲染以响应数据更改。
React 的核心概念是组件,它是一个独立的模块,用于呈现一些输出。组件可以独立嵌套、管理和处理,使开发过程高效且可维护。
在开始使用React之前,您需要设置开发环境。方法如下:
从官网下载并安装Node.js。
通过运行验证安装:
node -v npm -v
安装 Create React App:Create React App 是学习 React 的舒适环境,也是在 React 中启动新的单页应用程序的好方法。
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;
Lifecycle methods are special methods in class components that run at specific points in a component's life.
componentDidMount: Executed after the component is rendered.
componentDidUpdate: Executed after the component's updates are flushed to the DOM.
componentWillUnmount: Executed before the component is removed from the 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>; } }
The useEffect hook combines the functionalities of componentDidMount, componentDidUpdate, and 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 events are named using camelCase, rather than lowercase. With JSX, you pass a function as the event handler, rather than a string.
const handleClick = () => { console.log('Button clicked'); }; const MyComponent = () => { return <button onClick={handleClick}>Click me</button>; };
React's event system is known as Synthetic Events. It is a cross-browser wrapper around the browser's native event system.
Handling forms in React involves controlling the input elements and managing the state.
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;
Avoid inline event handlers: Define event handlers outside of the JSX for better readability and performance.
Use Arrow Functions: Use arrow functions to avoid issues with this binding.
Debounce Expensive Operations: Debounce expensive operations like API calls to avoid performance issues.
You can use JavaScript if-else statements inside the render method.
const MyComponent = ({ isLoggedIn }) => { if (isLoggedIn) { return <h1>Welcome back!</h1>; } else { return <h1>Please sign in.</h1>; } };
Ternary operators are a concise way to perform conditional rendering.
const MyComponent = ({ isLoggedIn }) => { return ( <div> {isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign in.</h1>} </div> ); };
You can use the logical && operator to include elements conditionally.
const MyComponent = ({ isLoggedIn }) => { return ( <div> {isLoggedIn && <h1>Welcome back!</h1>} </div> ); };
Inline if with logical && operator allows you to conditionally include an element in the output.
const Mailbox = ({ unreadMessages }) => { return ( <div> <h1>Hello!</h1> {unreadMessages.length > 0 && <h2> You have {unreadMessages.length} unread messages. </h2> } </div> ); };
You can build collections of elements and include them in JSX using curly braces {}.
const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); const NumberList = () => { return ( <ul>{listItems}</ul> ); };
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity.
const NumberList = (props) => { const numbers = props.numbers; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li> ); return ( <ul>{listItems}</ul> ); };
Keys used within arrays should be unique among their siblings.
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> ); }
Handling form data in React involves managing the state of the form fields.
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;
Controlled components are those that are controlled by React state. Uncontrolled components are those that maintain their own internal state.
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 provide a way to access DOM nodes or React elements created in the render method.
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> ); } }
Form validation ensures that user inputs are valid.
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 is a library for routing in React applications. It allows you to handle navigation and rendering of different components based on the URL.
Install React Router:
npm install react-router-dom
Set Up Routes:
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;
You can use route parameters to capture values from the 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;
Nested routes allow you to render sub-components within a parent component.
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;
You can use the Redirect component to redirect to a different route programmatically.
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;
The Context API provides a way to pass data through the component tree without having to pass props down manually at every level.
To create a context, use React.createContext.
const MyContext = React.createContext();
To consume a context value, use the useContext hook in functional components or Context.Consumer in class components.
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>; };
To update context, create a provider component with state.
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> ); };
Avoid overusing context: Use context sparingly and only for global data.
Use multiple contexts: Separate concerns by using multiple contexts.
Memoize context values: Use useMemo to avoid unnecessary re-renders.
Hooks are functions that let you use state and other React features in functional components.
useState: Adds state to functional components.
useEffect: Performs side effects in functional components.
useContext: Accesses context values.
useReducer: Manages complex state logic.
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> ); }
Custom hooks are functions that encapsulate logic and can be reused across components.
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>; };
Call hooks at the top level: Do not call hooks inside loops, conditions, or nested functions.
Only call hooks from React functions: Call hooks from functional components or custom hooks.
Higher-Order Components (HOC) are functions that take a component and return a new component.
HOCs are used to add additional functionality to components.
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);
Do not mutate the original component: Return a new component.
Use display names for debugging: Set displayName on the HOC for better debugging.
Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI.
Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.
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; } }
Error boundaries catch errors in the render method and in lifecycle methods.
const MyComponent = () => { throw new Error('An error occurred'); return <div>My Component</div>; }; const App = () => { return ( <ErrorBoundary> <MyComponent /> </ErrorBoundary> ); };
Use error boundaries to catch errors in components: Use error boundaries to catch and display errors in UI components.
Log errors for debugging: Log errors to external services for debugging.
Memoization helps to avoid re-rendering components unnecessarily.
import React, { memo } from 'react'; const MyComponent = memo(({ value }) => { return <div>{value}</div>; });
Code splitting helps to load only the necessary code and improve performance.
import React, { Suspense, lazy } from 'react'; const OtherComponent = lazy(() => import('./OtherComponent')); const MyComponent = () => { return ( <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> ); };
Lazy loading helps to load components only when they are needed.
import React, { Suspense, lazy } from 'react'; const Other Component = lazy(() => import('./OtherComponent')); const MyComponent = () => { return ( <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> ); };
useMemo: Memoizes expensive calculations.
useCallback: Memoizes functions.
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> ); };
Use React Developer Tools to identify performance bottlenecks.
Jest and React Testing Library are popular tools for testing React components.
Snapshot Testing: Capture the rendered component and compare it with a saved snapshot.
Unit Testing: Test individual components and functions.
Integration Testing: Test the integration between components and services.
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(); });
Organize components by feature: Group related components together.
Use descriptive names: Use clear and descriptive names for components and props.
Keep components small: Break down large components into smaller, reusable components.
Lift state up: Lift state to the nearest common ancestor.
使用 Context 进行全局状态:使用 Context API 进行全局状态管理。
使用 CSS 模块:使用 CSS 模块来实现作用域和模块化样式。
使用样式组件:使用样式组件进行动态样式设置。
避免不必要的重新渲染:使用记忆化和 React 内置的性能优化工具。
使用代码拆分:拆分代码以仅加载必要的组件。
编写全面的测试:为应用程序的所有关键部分编写测试。
使用快照测试:使用快照测试来捕获意外的更改。
React.js 是一个用于构建现代 Web 应用程序的强大库。通过理解和利用其核心概念,您可以构建高效、可维护和可扩展的应用程序。这份备忘单是帮助您掌握 React.js 的综合指南,涵盖从基本概念到高级主题的所有内容。
以上是面向开发人员的综合 React.js 备忘单的详细内容。更多信息请关注PHP中文网其他相关文章!