本文详细介绍了从零开始使用React 18进行项目开发的全过程,包括环境搭建、组件创建、状态管理、路由配置以及API数据请求等内容。同时,还涵盖了项目的打包部署和性能优化技巧,帮助你全面掌握React 18项目实战。React 18项目实战涉及的知识点全面且实用,适合初学者和有一定经验的开发者参考。
React 是由 Facebook 开发并维护的一个用于构建用户界面的 JavaScript 库。React 致力于提高开发效率与用户体验,通过声明式设计高效地构建用户界面,遵循“渐进式增强”的设计思路,使得开发者可以逐步提升应用的复杂度和性能。最新的 React 版本 React 18 带来了许多新特性,比如支持并发模式,改进了SSR和代码分割等,使得React在性能和易用性上得到了进一步的提升。
在开始使用React之前,需要先安装Node.js和npm(Node Package Manager)。Node.js 是一个开源的、跨平台的 JavaScript 运行环境,可以运行在服务端。npm 是 Node.js 的包管理器,可以通过 npm 安装和管理 React 和其他相关库。
检查安装是否成功:
node -v npm -v
确保 Node.js 和 npm 已经正确安装。
Create React App 是一个官方推荐的脚手架工具,用于快速搭建 React 项目。它提供了开箱即用的设置,包括构建工具、测试框架和开发服务器等功能。
npm install -g create-react-app
npx create-react-app my-app
这会创建一个名为 my-app
的 React 项目,并自动安装必要的依赖。
cd my-app
npm start
此时,浏览器会自动打开 http://localhost:3000
,展示新的 React 项目。
在 React 中,组件是构建用户界面的基本单位。每个组件通常包含一个输入(props)和一个输出(描述 UI 的 HTML 标签)。
src/components
目录下创建一个名为 HelloWorld.js
的新文件。// src/components/HelloWorld.js import React from 'react'; function HelloWorld() { return <h1>Hello, World!</h1>; } export default HelloWorld;
App.js
文件中引入并使用该组件:// src/App.js import React from 'react'; import HelloWorld from './components/HelloWorld'; function App() { return ( <div className="App"> <HelloWorld /> </div> ); } export default App;
此时,浏览器中的应用会显示 "Hello, World!"。
在 React 中,有两种主要的组件类型:函数组件和类组件。
函数组件是最简单的组件类型,它们是接收 props 作为输入并返回一个 UI 组件的函数。
// src/components/FuncComponent.js import React from 'react'; function FuncComponent(props) { return <h1>Hello, {props.name}!</h1>; } export default FuncComponent;
类组件是基于 ES6 类语法的组件,它不仅接收 props 作为输入,还可以包含内部状态和生命周期方法。
// src/components/ClassComponent.js import React, { Component } from 'react'; class ClassComponent extends Component { render() { return <h1>Hello, {this.props.name}!</h1>; } } export default ClassComponent;
属性是父组件传递给子组件的数据。子组件通过 props 接收数据,使用这些数据来渲染 UI。
// src/App.js import React from 'react'; import HelloWorld from './components/HelloWorld'; function App() { return ( <div className="App"> <HelloWorld name="Alice" /> <HelloWorld name="Bob" /> </div> ); } export default App;
状态是组件内部的数据,用于控制组件的行为。状态应该被视为不可变的,只能通过 setState 来更新。
// src/components/Counter.js import React, { Component } from 'react'; class Counter extends Component { constructor(props) { super(props); this.state = { count: 0 }; } increment = () => { this.setState({ count: this.state.count + 1 }); }; render() { return ( <div> <h1>Count: {this.state.count}</h1> <button onClick={this.increment}>Increment</button> </div> ); } } export default Counter;
React Hooks 是 React 16.8 引入的新特性,允许我们在不编写类的情况下使用状态和其他 React 特性。主要的 Hooks 包括 useState
、useEffect
、useContext
等。
useState
useState
允许我们在函数组件中使用状态。
// src/components/UseStateCounter.js import React, { useState } from 'react'; function UseStateCounter() { const [count, setCount] = useState(0); const increment = () => { setCount(count + 1); }; return ( <div> <h1>Count: {count}</h1> <button onClick={increment}>Increment</button> </div> ); } export default UseStateCounter;
useEffect
useEffect
允许我们执行副作用操作,如订阅、设置定时器、发送网络请求等。
// src/components/UseEffectExample.js import React, { useState, useEffect } from 'react'; function UseEffectExample() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); return ( <div> <h1>Count: {count}</h1> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); } export default UseEffectExample;
在 React 中,可以使用 props 将状态从父组件传递给子组件。
// src/components/ParentComponent.js import React, { useState } from 'react'; import ChildComponent from './ChildComponent'; function ParentComponent() { const [message, setMessage] = useState('Hello from Parent'); return ( <ChildComponent message={message} /> ); } export default ParentComponent;
// src/components/ChildComponent.js import React from 'react'; function ChildComponent(props) { return <h1>{props.message}</h1>; } export default ChildComponent;
Context API 用于在组件树中传递数据。它避免了在组件树中进行 prop drilling(即层层传递 props)。
// src/Context.js import React, { createContext, useContext, useState } from 'react'; const MyContext = createContext(); function MyProvider({ children }) { const [theme, setTheme] = useState('light'); return ( <MyContext.Provider value={{ theme, setTheme }}> {children} </MyContext.Provider> ); } export const useMyContext = () => useContext(MyContext); export { MyProvider };
// src/App.js import React from 'react'; import MyProvider from './Context'; import ChildComponent from './ChildComponent'; function App() { return ( <MyProvider> <ChildComponent /> </MyProvider> ); } export default App;
// src/components/ChildComponent.js import React from 'react'; import { useMyContext } from '../Context'; function ChildComponent() { const { theme, setTheme } = useMyContext(); return ( <div> <h1>{theme}</h1> <button onClick={() => setTheme('dark')}>Toggle Theme</button> </div> ); } export default ChildComponent;
Redux 是一个用于 JavaScript 应用的状态管理库,它通过单一的 store 来管理应用的所有状态。
npm install redux react-redux
// src/store.js import { createStore } from 'redux'; const initialState = { counter: 0, }; const rootReducer = (state = initialState, action) => { switch (action.type) { case 'INCREMENT': return { counter: state.counter + 1 }; case 'DECREMENT': return { counter: state.counter - 1 }; default: return state; } }; const store = createStore(rootReducer); export default store;
// src/components/Counter.js import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { increment, decrement } from '../actions'; function Counter() { const counter = useSelector((state) => state.counter); const dispatch = useDispatch(); return ( <div> <h1>Count: {counter}</h1> <button onClick={() => dispatch(increment())}>Increment</button> <button onClick={() => dispatch(decrement())}>Decrement</button> </div> ); } export default Counter;
App.js
中使用 Provider
:// src/App.js import React from 'react'; import { Provider } from 'react-redux'; import store from './store'; import Counter from './components/Counter'; function App() { return ( <Provider store={store}> <Counter /> </Provider> ); } export default App;
React Router 是一个用于 React 应用的路由库。它允许你定义应用的不同页面,并使用这些页面进行导航。
npm install react-router-dom
// src/App.js import React from 'react'; import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom'; import Home from './components/Home'; import About from './components/About'; import Contact from './components/Contact'; function App() { return ( <Router> <div> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> <li> <Link to="/contact">Contact</Link> </li> </ul> </nav> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/contact" component={Contact} /> </Switch> </div> </Router> ); } export default App;
// src/components/Home.js import React from 'react'; function Home() { return <h2>Home Page</h2>; } export default Home;
// src/components/About.js import React from 'react'; function About() { return <h2>About Page</h2>; } export default About;
// src/components/Contact.js import React from 'react'; function Contact() { return <h2>Contact Page</h2>; } export default Contact;
在 React Router 中,通过不同的路径配置可以实现页面的跳转。
// src/App.js import React from 'react'; import { BrowserRouter as Router, Route, Switch, Link, Redirect } from 'react-router-dom'; import Home from './components/Home'; import About from './components/About'; import Contact from './components/Contact'; import NotFound from './components/NotFound'; function App() { return ( <Router> <div> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/about">About</Link> </li> <li> <Link to="/contact">Contact</Link> </li> <li> <Link to="/notfound">Not Found</Link> </li> </ul> </nav> <Switch> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/contact" component={Contact} /> <Route path="/notfound" component={NotFound} /> <Redirect to="/" /> </Switch> </div> </Router> ); } export default App;
React Router 支持传递和使用路由参数。
// src/App.js import React from 'react'; import { BrowserRouter as Router, Route, Switch, Link, useParams } from 'react-router-dom'; import Home from './components/Home'; import User from './components/User'; function App() { return ( <Router> <div> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/user/1">User 1</Link> </li> <li> <Link to="/user/2">User 2</Link> </li> </ul> </nav> <Switch> <Route exact path="/" component={Home} /> <Route path="/user/:id" component={User} /> </Switch> </div> </Router> ); } export default App;
// src/components/User.js import React from 'react'; import { useParams } from 'react-router-dom'; function User() { const { id } = useParams(); return <h2>User: {id}</h2>; } export default User;
fetch
是浏览器内置的用于发送 HTTP 请求的方法,axios
是一个常用的 HTTP 客户端库。
fetch
// src/components/FetchData.js import React, { useEffect, useState } from 'react'; function FetchData() { const [data, setData] = useState(null); useEffect(() => { fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => response.json()) .then((data) => setData(data)) .catch((error) => console.error(error)); }, []); return ( <div> {data ? <pre>{JSON.stringify(data, null, 2)}</pre> : 'Loading...'} </div> ); } export default FetchData;
axios
// src/components/AxiosData.js import React, { useEffect, useState } from 'react'; import axios from 'axios'; function AxiosData() { const [data, setData] = useState(null); useEffect(() => { axios.get('https://jsonplaceholder.typicode.com/todos/1') .then((response) => setData(response.data)) .catch((error) => console.error(error)); }, []); return ( <div> {data ? <pre>{JSON.stringify(data, null, 2)}</pre> : 'Loading...'} </div> ); } export default AxiosData;
在处理异步数据时,需要关注请求的响应和错误处理。
// src/components/FetchDataWithError.js import React, { useEffect, useState } from 'react'; function FetchDataWithError() { const [data, setData] = useState(null); const [error, setError] = useState(null); useEffect(() => { fetch('https://jsonplaceholder.typicode.com/todos/1') .then((response) => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then((data) => setData(data)) .catch((error) => { setError(error); console.error('There was an error!', error); }); }, []); if (error) { return <div>Error: {error.message}</div>; } if (!data) { return <div>Loading...</div>; } return ( <div> <pre>{JSON.stringify(data, null, 2)}</pre> </div> ); } export default FetchDataWithError;
使用 useEffect
和 setState
,可以实现数据的实时更新。
// src/components/RealtimeData.js import React, { useEffect, useState } from 'react'; import axios from 'axios'; function RealtimeData() { const [data, setData] = useState(null); useEffect(() => { const intervalId = setInterval(() => { axios.get('https://jsonplaceholder.typicode.com/todos/1') .then((response) => setData(response.data)) .catch((error) => console.error(error)); }, 5000); return () => clearInterval(intervalId); }, []); if (!data) { return <div>Loading...</div>; } return ( <div> <pre>{JSON.stringify(data, null, 2)}</pre> </div> ); } export default RealtimeData;
使用 npm run build
命令打包项目,生成的 build
目录下的文件可以直接部署到生产环境。
npm run build
生成的文件可以部署到任何静态文件服务器,如 AWS S3、Netlify、Vercel 等。
aws s3 cp build/ s3://your-bucket-name --recursive
netlify deploy --dir=build
vercel --prod
import()
语法进行动态导入,按需加载模块。import("./myComponent").then(module => { const MyComponent = module.default; render(<MyComponent />); });
lazy
函数实现组件的懒加载。import React from 'react'; const MyComponent = React.lazy(() => import('./MyComponent')); function App() { return ( <React.Suspense fallback={<div>Loading...</div>}> <MyComponent /> </React.Suspense> ); }
import { useRouter } from 'next/router'; import React from 'react'; function MyComponent() { const router = useRouter(); const { id } = router.query; // fetch data using id return <div>Component with {id}</div>; } export async function getServerSideProps(context) { const { id } = context.query; // fetch data using id return { props: { id } }; } export default MyComponent;
res.setHeader('Cache-Control', 's-maxage=31536000, stale-while-revalidate=2592000');
module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', }, }, { test: /\.css$/, use: ['style-loader', 'css-loader'], }, { test: /\.(png|jpe?g|gif)$/i, use: [ { loader: 'file-loader', options: { name: '[name].[hash].[ext]', outputPath: 'images/', }, }, ], }, ], }, plugins: [ new MiniCssExtractPlugin({ filename: '[name].css', }), ], };
环境变量可以帮助你在开发和生产环境中使用不同的配置。
.env
文件:# .env REACT_APP_API_URL=https://api.example.com REACT_APP_ENV=development
import React from 'react'; import axios from 'axios'; const apiBaseUrl = process.env.REACT_APP_API_URL; function MyComponent() { return <div>API URL: {apiBaseUrl}</div>; } export default MyComponent;
以上内容详细介绍了从零开始使用 React 18 创建一个完整项目的整个过程,包括安装环境、创建组件、状态管理、路由配置、数据请求、项目部署与优化等。希望对你有所帮助。