Hi,我是前端人类学! React 是由 Facebook 开发并维护的一个用于构建用户界面的 JavaScript 库。自2013年5月首次发布以来,React 因其高效性、灵活性和强大的生态系统而广受欢迎。React 不仅可以用于构建 Web 应用程序,还可以通过 React Native 构建移动应用程序。本文将详细介绍 React 的核心概念、生命周期方法、最新特性以及最佳实践,帮助读者全面掌握这一强大的前端工具。
一、官方网站
React 的官方网站是 react.docschina.org/。在这里,你可以找到官方文档、教程、API 参考以及社区资源。
二、安装React
2.1 使用 Create React App
Create React App
是一个官方支持的脚手架工具,可以帮助你快速搭建一个 React 应用程序。以下是安装步骤:
-
确保已安装 Node.js :首先确保你的机器上已经安装了 Node.js。你可以通过运行以下命令来检查:
shnode -v npm -v
-
安装 Create React App :打开终端或命令行工具,运行以下命令来全局安装 Create React App:
shnpx create-react-app my-app
-
进入项目目录 :
shcd my-app
-
启动开发服务器 :
shnpm start
这将启动一个本地开发服务器,并在浏览器中打开
http://localhost:3000
,你将看到一个默认的 React 应用程序。
2.2 手动安装
如果你不想使用 Create React App,也可以手动安装 React 和相关依赖。以下是步骤:
-
初始化项目 :
shmkdir my-app cd my-app npm init -y
-
安装 React 和 React DOM :
shnpm install react react-dom
-
创建入口文件 :在项目根目录下创建一个 index.html 文件:
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>React App</title> </head> <body> <div id="root"></div> <script src="./index.js"></script> </body> </html>
-
创建主 JavaScript 文件 :在项目根目录下创建一个 index.js 文件:
javascriptimport React from 'react'; import ReactDOM from 'react-dom'; const App = () => { return <h1>Hello, React!</h1>; }; ReactDOM.render(<App />, document.getElementById('root'));
-
启动开发服务器 :你可以使用
webpack
或其他模块打包工具来启动开发服务器。这里以webpack
为例:shnpm install --save-dev webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react
-
配置 Webpack :在项目根目录下创建一个 webpack.config.js 文件:
javascriptconst path = require('path'); module.exports = { entry: './index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] } };
-
配置 Babel :在项目根目录下创建一个 .babelrc 文件:
json{ "presets": ["@babel/preset-env", "@babel/preset-react"] }
-
添加启动脚本 :在 package.json 中添加一个启动脚本:
json"scripts": { "start": "webpack serve --open" }
-
启动开发服务器 :
bashnpm start
三、React 核心概念
3.1 组件化
React 的核心理念之一是组件化。组件化意味着将复杂的用户界面分解为多个小的、可重用的组件。每个组件负责渲染一部分 UI,并且可以拥有自己的逻辑和状态。组件之间通过属性(Props)进行通信,形成树状结构。
-
函数组件 :使用简单的函数定义,接收输入参数(Props),返回要渲染的元素。从 React 16.8 开始,函数组件可以通过 Hooks 使用状态和其他功能。
javascriptfunction Welcome(props) { return <h1>Hello, {props.name}</h1>; }
-
类组件 :继承自
React.Component
类,可以通过this.state
和this.props
访问状态和属性。javascriptclass Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
3.2 JSX
JSX 是一种扩展语法,允许在 JavaScript 中编写类似于 HTML 的标记语言。实际上,JSX 会被编译成普通的 JavaScript 函数调用,通常是 React.createElement()
。
-
基本语法 :
javascriptconst element = <h1>Hello, world!</h1>;
-
嵌入式表达 :
javascriptconst name = 'Josh Perez'; const element = <h1>Hello, {name}</h1>;
3.3 虚拟DOM
虚拟 DOM 是 React 内部使用的轻量级 DOM 树副本。当组件的状态或属性发生变化时,React 会先在虚拟 DOM 上进行更改,然后通过高效的算法计算出最小的更新操作,最后将这些操作应用到真实的 DOM 上,从而减少不必要的 DOM 操作,提高性能。
3.4 Props 和 State
-
Props :属性(Properties)是从父组件传递给子组件的数据。Props 是不可变的,子组件不能修改它接收到的 Props。
javascriptfunction ChildComponent(props) { return <div>{props.message}</div>; } function ParentComponent() { return <ChildComponent message="Hello from parent!" />; }
-
State :状态是组件内部用来存储数据的对象。它可以随时改变,当状态变化时,React 会自动重新渲染组件以反映最新的状态。
javascriptclass Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } increment = () => { this.setState({ count: this.state.count + 1 }); } render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.increment}>Increment</button> </div> ) } }
四、生命周期方法
React 组件的生命周期可以分为三个主要阶段:挂载、更新和卸载。每个阶段都有相应的生命周期方法,这些方法可以在特定的时间点执行特定的操作。
- 挂载阶段 :
constructor(props)
:构造函数,在组件实例创建时调用。static getDerivedStateFromProps(nextProps, prevState)
:静态方法,在每次渲染之前调用,用于根据新的 Props 更新 State。render()
:渲染方法,返回要显示的 UI。componentDidMount()
:组件挂载后调用,通常用于发起网络请求或设置定时器。
- 更新阶段 :
static getDerivedStateFromProps(nextProps, prevState)
:在每次渲染前调用,用于根据新的 Props 更新 State。shouldComponentUpdate(nextProps, nextState)
:决定组件是否需要重新渲染,默认返回 true。render()
:重新渲染组件。getSnapshotBeforeUpdate(prevProps, prevState)
:在最近一次渲染输出(提交到 DOM 节点)之前调用,可以捕获 DOM 变化前的信息。componentDidUpdate(prevProps, prevState, snapshot)
:组件更新后调用,通常用于更新 DOM 或发起网络请求。
- 卸载阶段 :
componentWillUnmount()
:组件卸载前调用,用于清理定时器、取消网络请求等操作。
五、新特性介绍
5.1 Hooks
Hooks 是 React 16.8 版本引入的新特性,允许在不编写类的情况下使用状态和其他 React 功能。Hooks 主要包括以下几种:
-
useState :用于声明状态变量。
javascriptimport React, { useState } from 'react'; function Example() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ) }
-
useEffect :用于执行副作用操作,如数据获取、订阅或手动更改 DOM。
javascriptimport React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }) return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ) }
-
useContext :用于访问 React 的上下文(Context)。
javascriptimport React, { useContext } from 'react'; const ThemeContext = React.createContext('light'); function ThemedButton() { const theme = useContext(ThemeContext); return <button style={{ background: theme }}>Themed Button</button>; }
5.2 Context API
Context API 提供了一种在组件树中传递数据的方式,而无需手动地通过 Props 逐层传递。这对于大型应用中的全局状态管理非常有用。
-
创建 Context :
javascriptconst MyContext = React.createContext(defaultValue);
-
提供者(Provider) :
javascript<MyContext.Provider value={value}> {/* 子组件 */} </MyContext.Provider>
-
消费者(Consumer) :
javascript<MyContext.Consumer> {value => /* 基于 context 值的 UI */} </MyContext.Consumer>
-
useContext Hook :
javascriptconst value = useContext(MyContext);
六、状态管理
在复杂的应用中,状态管理变得尤为重要。React 提供了几种不同的状态管理解决方案,包括但不限于:
6.1 Redux
Redux 是一个用于管理应用状态的库,常与 React 一起使用。它通过一个全局的 store 来集中管理应用的状态。
-
安装 Redux :
bashnpm install redux react-redux
-
创建 Store :
javascriptimport { createStore } from 'redux'; const initialState = { counter: 0 }; const reducer = (state = initialState, action) => { switch (action.type) { case 'INCREMENT': return { ...state, counter: state.counter + 1 }; case 'DECREMENT': return { ...state, counter: state.counter - 1 }; default: return state; } } const store = createStore(reducer)
-
连接组件
javascriptimport React from 'react'; import { useSelector, useDispatch } from 'react-redux'; function Counter() { const counter = useSelector(state => state.counter); const dispatch = useDispatch(); return ( <div> <p>Counter: {counter}</p> <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button> <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button> </div> ) } export default Counter
6.2 Mobx
MobX 是一个简单、透明的状态管理库,它通过可观察对象和反应式视图来管理状态。
-
安装 MobX :
bashnpm install mobx mobx-react
-
创建 Store :
javascriptimport { makeAutoObservable } from 'mobx'; class CounterStore { counter = 0; constructor() { makeAutoObservable(this); } increment = () => { this.counter += 1; } decrement = () => { this.counter -= 1; } } const counterStore = new CounterStore()
-
连接组件 :
javascriptimport React from 'react'; import { observer } from 'mobx-react'; import { counterStore } from './stores/CounterStore'; const Counter = observer(() => { return ( <div> <p>Counter: {counterStore.counter}</p> <button onClick={counterStore.increment}>Increment</button> <button onClick={counterStore.decrement}>Decrement</button> </div> ) }) export default Counter
6.3 React Context API
React 的 Context API 也可以用于状态管理,特别是在中小型应用中。虽然它不如 Redux 和 MobX 强大,但对于简单的状态管理需求已经足够。
-
创建 Context :
javascriptimport React, { createContext, useState } from 'react'; const CounterContext = createContext(); const CounterProvider = ({ children }) => { const [counter, setCounter] = useState(0); const increment = () => setCounter(counter + 1); const decrement = () => setCounter(counter - 1); return ( <CounterContext.Provider value={{ counter, increment, decrement }}> {children} </CounterContext.Provider> ) } export { CounterContext, CounterProvider }
-
使用 Context :
javascriptimport React, { useContext } from 'react'; import { CounterContext } from './CounterContext'; const Counter = () => { const { counter, increment, decrement } = useContext(CounterContext); return ( <div> <p>Counter: {counter}</p> <button onClick={increment}>Increment</button> <button onClick={decrement}>Decrement</button> </div> ) } export default Counter
七、最佳实践
7.1 组件划分
保持组件的小型化和单一职责原则,有助于提高代码的可读性和可维护性。小型组件更容易测试和复用。
7.2 代码复用
-
高阶组件(HOCs) :高阶组件是一个函数,接受一个组件并返回一个新的组件。HOCs 可以用于封装共享逻辑。
javascriptfunction withLoading(WrappedComponent) { return function EnhancedComponent(props) { if (props.isLoading) { return <div>Loading...</div>; } return <WrappedComponent {...props} />; } }
-
Render Props :Render Props 是一种在 React 组件之间共享代码的技术,通过将函数作为 props 传递来实现。
javascriptclass MouseTracker extends React.Component { // ... render() { return this.props.render(this.state.mousePosition); } } function App() { return ( <MouseTracker render={mousePosition => ( <h1>The mouse position is {mousePosition.x}, {mousePosition.y}</h1> )} /> ) }
7.3 性能优化
-
React.memo :用于函数组件,如果 Props 没有变化,则跳过渲染。
javascriptconst MyComponent = React.memo(function MyComponent(props) { /* 渲染使用 props 的 UI */ })
-
useMemo :用于缓存计算结果,避免重复计算。
javascriptfunction MyComponent(props) { const memoizedValue = useMemo(() => computeExpensiveValue(props), [props]); // ... }
7.4 错误边界
错误边界是一种 React 组件,可以捕获并处理其子组件树中任何地方抛出的 JavaScript 错误。错误边界可以防止整个应用崩溃。
-
定义边界错误 :
javascriptclass ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { logErrorToMyService(error, errorInfo); } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } }
-
使用边界错误 :
javascript<ErrorBoundary> <MyWidget /> </ErrorBoundary>
掌握其核心概念和最佳实践对于构建高效、可维护的应用至关重要。希望本文能帮助读者全面理解和运用 React,构建出优秀的用户界面。