React框架基础教程
目录
简介
- React概述
- 优势与应用场景
环境准备
- Node.js安装
- 创建React应用程序
React基础
- JSX语法
- 组件
- 状态与属性
- 事件处理
组件生命周期
- 挂载、更新、卸载
- 错误边界
状态管理
- useState钩子
- useEffect钩子
- Context API
路由管理
- React Router介绍
- 路由配置
表单与受控组件
- 表单基础知识
- 受控组件与非受控组件
样式与布局
- 内联样式
- CSS模块
- 布局技巧
动画与过渡
- React Transition Group
- 动画示例
测试与优化
- Jest与Enzyme
- 性能优化
部署
- 准备工作
- 部署到服务器
附录
- 推荐资源
- 常见问题解答
示例代码:Todo应用程序
1. 创建组件
import React from 'react';
const TodoList = ({ todos, deleteTodo }) => {
return (
<ul>
{todos.map((todo, index) => (
<li key={index}>
{todo}
<button onClick={() => deleteTodo(index)}>删除</button>
</li>
))}
</ul>
);
};
const AddTodo = ({ addTodo }) => {
const [value, setValue] = React.useState('');
const handleSubmit = e => {
e.preventDefault();
if (!value) return;
addTodo(value);
setValue('');
};
return (
<form onSubmit={handleSubmit}>
<input type="text" value={value} onChange={e => setValue(e.target.value)} />
<button type="submit">添加</button>
</form>
);
};
2. 使用组件
import React, { useState } from 'react';
import './App.css';
import TodoList from './TodoList';
import AddTodo from './AddTodo';
const App = () => {
const [todos, setTodos] = useState([]);
const addTodo = text => {
const newTodos = [...todos, text];
setTodos(newTodos);
};
const deleteTodo = index => {
const newTodos = [...todos];
newTodos.splice(index, 1);
setTodos(newTodos);
};
return (
<div className="App">
<AddTodo addTodo={addTodo} />
<TodoList todos={todos} deleteTodo={deleteTodo} />
</div>
);
};
export default App;
2. 环境准备
在开始使用React之前,我们需要准备开发环境。这包括安装Node.js、创建新的React应用程序等步骤。
步骤 1: 安装Node.js
访问Node.js官网(https://nodejs.org/)下载并安装最新版本的Node.js。Node.js是一个JavaScript运行环境,它让我们可以在服务器端运行JavaScript。
步骤 2: 创建React应用程序
使用Create React App脚手架工具可以快速创建一个新的React应用程序。打开命令行工具,运行以下命令:
npx create-react-app my-app
这个命令会创建一个名为my-app
的新目录,并在该目录下创建一个完整的React应用程序。
3. React基础
JSX语法
React使用JSX来描述页面结构。JSX是一种JavaScript的语法扩展,它允许我们在JavaScript中编写HTML。
示例
以下是一个简单的React组件,它使用JSX描述了一个按钮和一段文本:
const MyComponent = () => {
return (
<div>
<button>Click me</button>
<p>Hello, world!</p>
</div>
);
};
组件
React的核心概念是组件。一个组件是一个自包含的代码单元,它返回一些JSX来描述页面的一部分。
示例
我们可以通过创建一个新函数来创建一个新的组件:
const Button = () => {
return <button>Click me</button>;
};
然后在其他组件中使用<Button />
标签来引用这个组件。
状态与属性
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>
);
};
在这个组件中,count
是状态,setCount
是一个更新状态的函数。我们通过点击按钮来增加计数器的值。
事件处理
React使用JavaScript的合成事件系统来处理DOM事件。这让我们可以使用一种统一的方式处理鼠标、键盘等事件。
示例
以下组件在点击时打印一条消息:
const MyComponent = () => {
function handleClick() {
console.log('You clicked me');
}
return (
<button onClick={handleClick}>Click me</button>
);
};
在这个组件中,我们定义了一个handleClick
函数来处理点击事件。然后我们在JSX中通过onClick
属性将这个函数绑定到按钮上。
3. 组件生命周期
React组件拥有一个生命周期,从创建到销毁过程中会经历多个阶段。理解这些阶段有助于我们在正确的时间执行适当的操作。
挂载阶段
constructor
:构造函数,用于初始化状态或绑定事件处理器。getDerivedStateFromProps
:根据属性变化派生状态,静态函数,不改变对象属性。render
:渲染函数,纯函数,返回JSX描述的UI界面。componentDidMount
:组件已挂载到DOM后执行,常用来发起网络请求或设置订阅。
更新阶段
getDerivedStateFromProps
:根据新旧属性派生新状态。shouldComponentUpdate
:确定是否重新渲染组件,根据新旧属性和状态判断。render
:重新渲染组件。getSnapshotBeforeUpdate
:在DOM更新前获取快照,常用于滚动恢复等。componentDidUpdate
:组件更新后执行,可进行DOM操作、发起网络请求等。
卸载阶段
componentWillUnmount
:组件被卸载前执行,用于清理定时器、订阅、事件监听等。
错误处理
static getDerivedStateFromError
:捕获子组件树中的错误,并返回新的state。componentDidCatch
:捕获子组件树中的错误,并在此处记录错误信息。
示例
class MyClassComponent extends React.Component {
componentDidMount() {
console.log('Component mounted');
}
componentDidUpdate() {
console.log('Component updated');
}
componentWillUnmount() {
console.log('Component will unmount');
}
render() {
return <div>Hello, world!</div>;
}
}
4. 状态管理
React提供了多种状态管理方案,包括使用useState
和useEffect
钩子,以及Context API
。
useState
useState
是React的一个钩子,用于在函数组件中声明状态变量。
示例
import React, { useState } from 'react';
function MyFunctionComponent() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
useEffect
useEffect
钩子用于在函数组件中处理副作用,如数据获取、订阅等。
示例
import React, { useState, useEffect } from 'react';
function MyFunctionComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData().then(setData);
}, []);
return (
<div>
{data ? data : 'Loading...'}
</div>
);
}
Context API
Context API
允许我们不必通过props逐层传递属性,直接在组件树间共享数据。
示例
import React, { createContext, useContext } from 'react';
const MyContext = createContext();
function MyProvider({ children }) {
const value = 'Shared value';
return (
<MyContext.Provider value={value}>
{children}
</MyContext.Provider>
);
}
function MyConsumer() {
const value = useContext(MyContext);
return <div>{value}</div>;
}
function App() {
return (
<MyProvider>
<MyConsumer />
</MyProvider>
);
}
5. 路由管理
在多页面应用中,路由管理是必不可少的一环。React通过React Router
库来处理客户端路由。
React Router介绍
React Router
是一个独立的npm包,它与React紧密结合,提供了声明式路由管理。
示例
首先,安装react-router-dom
:
npm install react-router-dom
然后,创建基本的路由配置:
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
const Home = () => <h2>Home</h2>;
const About = () => <h2>About</h2>;
const App = () => (
<Router>
<div>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about/">About</Link></li>
</ul>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about/" component={About} />
</div>
</Router>
);
export default App;
在这个示例中,我们定义了两个简单的组件Home
和About
,并在App
组件中使用Route
来配置路由。
6. 表单与受控组件
在React中,表单和它们的输入元素可以通过“受控组件”来进行管理。这意味着组件的状态控制着输入元素的值。
示例
import React, { useState } from 'react';
function MyForm() {
const [username, setUsername] = useState('');
const handleSubmit = event => {
event.preventDefault();
console.log('Username:', username);
};
return (
<form onSubmit={handleSubmit}>
<label>
Username:
<input
type="text"
value={username}
onChange={e => setUsername(e.target.value)}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
export default MyForm;
在这个示例中,username
状态控制着输入框的值,当用户输入时,onChange
事件处理器更新状态。
7. 样式与布局
React应用中可以使用各种方式来处理样式和布局,包括内联样式、CSS模块和CSS-in-JS解决方案。
内联样式
import React from 'react';
function MyComponent() {
return <div style={{ color: 'red', fontSize: '20px' }}>Styled Component</div>;
}
export default MyComponent;
CSS模块
首先,创建一个CSS模块文件MyComponent.module.css
:
/* MyComponent.module.css */
.myClass {
color: red;
fontSize: 20px;
}
然后,在组件中导入并使用它:
import React from 'react';
import styles from './MyComponent.module.css'; // 导入CSS模块
function MyComponent() {
return <div className={styles.myClass}>Styled Component</div>;
}
export default MyComponent;
CSS-in-JS
使用像styled-components
这样的库,可以更灵活地管理组件的样式:
npm install styled-components
import React from 'react';
import styled from 'styled-components';
const StyledDiv = styled.div`
color: red;
font-size: 20px;
`;
function MyComponent() {
return <StyledDiv>Styled Component</StyledDiv>;
}
export default MyComponent;
8. 动画与过渡
在用户界面中添加动画和过渡效果可以提升用户体验。React通过添加特定的CSS类或使用React库来实现动画效果。
使用CSS的过渡
首先,为元素添加样式以实现过渡效果:
.element {
transition: background-color 1s ease;
background-color: lightgray; /* 初始状态 */
}
.element.highlighted {
background-color: blue; /* 结束状态 */
}
然后,在React组件中动态添加或移除highlighted
类:
import React, { useState } from 'react';
function MyComponent() {
const [isHighlighted, setIsHighlighted] = useState(false);
return (
<div
className={`element ${isHighlighted ? 'highlighted' : ''}`}
onClick={() => setIsHighlighted(!isHighlighted)}
>
Click me
</div>
);
}
export default MyComponent;
使用React Transition Group
react-transition-group
是一个用于处理复杂过渡效果的第三方库。
首先,安装react-transition-group
:
npm install react-transition-group
然后,在组件中使用TransitionGroup
和CSSTransition
:
import React, { useState } from 'react';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
function MyComponent() {
const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']);
return (
<TransitionGroup>
{items.map((item, index) => (
<CSSTransition
key={index}
timeout={500}
classNames="item"
>
<div>{item}</div>
</CSSTransition>
))}
</TransitionGroup>
);
}
export default MyComponent;
在这个示例中,当列表项改变时,会有一个动画过渡效果。
9. 测试与优化
为了确保React应用的稳定性和性能,我们需要进行测试和优化。
测试
React应用可以使用Jest和Enzyme等工具进行单元测试和快照测试。
首先,安装Jest和Enzyme:
npm install --save-dev jest enzyme enzyme-to-json
然后,编写一个简单的测试用例:
import React from 'react';
import { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import MyComponent from './MyComponent';
describe('<MyComponent />', () => {
it('renders without crashing', () => {
shallow(<MyComponent />);
});
it('renders the UI as expected', () => {
const wrapper = shallow(<MyComponent />);
const json = toJson(wrapper);
expect(json).toMatchSnapshot();
});
});
优化
性能优化可以从减少不必要的重新渲染、使用PureComponent、使用React.memo等方法入手。
import React from 'react';
class MyPureComponent extends React.PureComponent {
render() {
// ...
}
}
const MyMemoComponent = React.memo(function MyComponent(props) {
// ...
});
10. 部署
开发完成后,我们需要将React应用部署到服务器上。以下是部署React应用的一般步骤:
第一步:构建生产环境代码
在package.json
中添加一个构建脚本:
"scripts": {
"build": "react-scripts build"
}
然后运行构建命令:
npm run build
这会创建一个build
文件夹,包含优化后的React应用。
第二步:选择托管服务
可以选择多种服务来托管你的React应用,比如Netlify、Vercel、GitHub Pages或AWS S3。
第三步:部署到Netlify
以Netlify为例,首先在Netlify官网注册账号并登录,然后点击“New site from Git”。
连接你的Git仓库(例如GitHub),选择存储React应用代码的分支和目录。
点击“Deploy site”,等待Netlify部署你的应用。
部署完成后,你就可以在Netlify提供的网址上访问你的React应用了。
第四步:使用HTTPS
为了安全,建议使用HTTPS来服务你的React应用。可以在Netlify的设置中启用HTTPS。
第五步:配置域名
你可以购买一个域名,并在Netlify中配置CNAME记录,将域名解析到你的React应用。
11. 性能优化
为了提升React应用的性能,我们可以采取以下策略:
避免不必要的重新渲染
使用shouldComponentUpdate
或React.PureComponent
来避免不必要的子组件重新渲染。
代码分割
使用动态import()
语法来实现代码分割,减少初始加载时间。
懒加载
对于不是立即需要的模块,可以使用Webpack的babel-plugin-syntax-dynamic-import
插件进行懒加载。
使用缓存
利用浏览器缓存机制,为静态资源设置缓存头。
优化状态管理
避免频繁的Redux actions和reducers,尽量在组件内部处理状态。
使用负载组件
在数据加载时显示负载组件,提升用户体验。
12. React Hooks
React Hooks是一个新的特性,它允许你在不使用类的情况下使用状态和其他React特性。
使用State Hook
import 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>
);
}
使用Effect Hook
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 只有count变化时才执行
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
13. 高级概念
在React中,还有一些高级概念可以帮助我们更好地理解和使用这个框架。
Context API
Context API
是React提供的一种跨组件传递数据的方式。它可以避免通过props逐层传递数据。
import React, { createContext, useState } from 'react';
const ThemeContext = createContext();
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Header />
<Content />
</ThemeContext.Provider>
);
}
function Header() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<div>
<button onClick={() => setTheme('dark')}>Dark Mode</button>
<button onClick={() => setTheme('light')}>Light Mode</button>
</div>
);
}
function Content() {
const { theme } = useContext(ThemeContext);
return (
<div style={{ backgroundColor: theme === 'dark' ? 'black' : 'white' }}>
This is the content area.
</div>
);
}
Redux
Redux
是一个用于管理应用状态的库,它可以与React一起使用。
首先,安装Redux:
npm install redux react-redux
然后,创建一个简单的Redux store:
import { createStore } from 'redux';
const initialState = { count: 0 };
function reducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
default:
return state;
}
}
const store = createStore(reducer);
接下来,将store传递给React应用:
import React from 'react';
import { Provider } from 'react-redux';
import store from './store';
import MyComponent from './MyComponent';
function App() {
return (
<Provider store={store}>
<MyComponent />
</Provider>
);
}
最后,在组件中使用Redux的状态和actions:
import React from 'react';
import { connect } from 'react-redux';
function MyComponent({ count, increment }) {
return (
<div>
<p>You clicked {count} times</p>
<button onClick={increment}>Click me</button>
</div>
);
}
const mapStateToProps = state => ({ count: state.count });
const mapDispatchToProps = dispatch => ({
increment: () => dispatch({ type: 'INCREMENT' }),
});
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
以上内容介绍了React中的高级概念,包括Context API和Redux的基本概念和用法。