React 是一个用于构建用户界面的 JavaScript 库,特别适用于单页应用程序(SPA)。它由 Facebook 维护,并以其高性能和声明式视图而闻名。
Create React App
是官方推荐的方式来快速启动一个新的 React 项目。确保你已经安装了 Node.js 和 npm。
bashnpx create-react-app my-app
cd my-app
npm start
这会创建一个新目录 my-app
并安装所有必要的依赖项。完成后,你的应用将会在浏览器中自动打开并运行在 http://localhost:3000
上。
JSX 是一种 JavaScript 的语法扩展,允许你在 JavaScript 中编写类似 HTML 的代码。每个 JSX 元素都是转换为 React.createElement()
调用的表达式。
jsxconst element = <h1>Hello, world!</h1>;
组件是 React 应用的基本构建块。它们可以是函数或类的形式定义。
jsxfunction Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
jsxclass Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
useState
Hook 在函数组件中使用。jsximport React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Hooks 是 React 16.8 引入的新功能,允许你在不编写类的情况下使用状态和其他 React 特性。
useState
:如上所示,用于声明状态变量。useEffect
:执行副作用操作,比如数据获取、订阅或手动 DOM 操作等。jsximport 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>
);
}
根据不同的条件显示不同的 UI 元素。
jsxfunction Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <h1>Hello, user!</h1>;
}
return <h1>Please sign up.</h1>;
}
使用 map()
方法来遍历数组并生成列表。
jsxconst numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>{number}</li>
);
受控组件是指其值通过 React 状态管理的表单元素。
jsxclass 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>
);
}
}
对于类组件,你可以利用生命周期方法来控制组件的行为。
componentDidMount()
:组件挂载后调用。componentDidUpdate()
:组件更新后调用。componentWillUnmount()
:组件卸载前调用。jsxclass Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
高阶组件是 React 中用于复用组件逻辑的一种高级技术。它是一个函数,接受一个组件并返回一个新的组件。
jsxfunction withLogging(WrappedComponent) {
return class extends React.Component {
componentDidMount() {
console.log(`Logging: ${WrappedComponent.name} has mounted`);
}
render() {
return <WrappedComponent {...this.props} />;
}
};
}
// 使用 HOC
const EnhancedComponent = withLogging(MyComponent);
渲染属性是一种通过使用一个值为函数的 prop 来共享代码的技术。
render
prop 实现鼠标位置追踪jsxclass MouseTracker extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div onMouseMove={this.handleMouseMove}>
{/*
Instead of providing a static representation of what <Mouse> renders,
use the `render` prop to dynamically determine what to render.
*/}
{this.props.render(this.state)}
</div>
);
}
}
// 使用 MouseTracker 组件
<MouseTracker render={mouse => (
<h1>The mouse position is ({mouse.x}, {mouse.y})</h1>
)}/>
Context 提供了一种在组件树中传递数据的方法,而无需手动通过每个层级的 props 传递。
jsxconst MyContext = React.createContext(defaultValue);
jsxclass App extends React.Component {
render() {
return (
<MyContext.Provider value="Hello from context!">
<Toolbar />
</MyContext.Provider>
);
}
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
static contextType = MyContext;
render() {
return <button>{this.context}</button>;
}
}
或者使用 useContext
Hook:
jsxfunction ThemedButton() {
const value = React.useContext(MyContext);
return <button>{value}</button>;
}
Redux 是一个可预测的状态容器,适用于 JavaScript 应用程序。它帮助你编写行为一致的应用程序,使其易于测试,并能在不同环境(客户端、服务器端)运行。
bashnpm install redux react-redux
javascriptimport { createStore } from 'redux';
function counterReducer(state = { count: 0 }, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
default:
return state;
}
}
const store = createStore(counterReducer);
javascriptimport React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App'; // 假设这是你的主组件
import store from './store'; // 引入你创建的 Redux store
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
使用 connect()
函数或 useSelector
和 useDispatch
Hooks。
javascriptimport { useSelector, useDispatch } from 'react-redux';
function Counter() {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<p>{count}</p>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
</div>
);
}
React Router 是官方推荐的路由库,它允许你在 React 应用中实现导航功能。
bashnpm install react-router-dom
jsximport { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
function App() {
return (
<Router>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
jsximport { Link } from 'react-router-dom';
<Link to="/about">About</Link>
使用 Jest 和 React Testing Library 来测试 React 组件。
bashnpm install --save-dev jest @testing-library/react @testing-library/jest-dom
javascriptimport React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});