从零搭建React全家桶框架教程:快速搭建react+react-router+redux项目

搭建基本的react项目
  1. 我们使用create-react-app(npm要全局安装create-react-app)快速创建一个react项目:
npx create-react-app my-app
cd my-app
npm start

启动成功后,就可以看到react的页面啦。接下来我们稍稍调整下项目的目录结构和页面内容,新增About页面。

  1. 在src目录下新建pages目录,用来放置前端页面。新建App目录,将原来App.js和App.css移动进去,注意这两个文件引入路径的修改。


    项目目录结构图
  2. 在src目录下新增Home页面和About页面(后面用到)

// 路径:/src/pages/Home/Home.js
import React from 'react'const Home = () => (<div><h1>Home Page</h1><p>这是Home页面</p></div>
)export default Home
// 路径:/src/pages/About/About.js
import React from 'react'const About = () => (<div><h1>About Page</h1><p>这是About页面</p></div>
)export default About
接入react-router

接下来,我们开始在项目中接入react-router,通过npm指令安装"react-router"和"react-router-dom":

npm i -S react-router react-router-dom
  1. 我们修改一下/src/pages/App/App.js/src/index.js的内容:
// /src/pages/App/App.js
import React from 'react'
import { Route, Link } from 'react-router-dom'
import Home from '../Home/Home'
import About from '../About/About'const App = () => (<div><header><Link to="/">Home</Link>&nbsp;<Link to="/about">About</Link></header><main><Route exact path="/" component={Home} /><Route exact path="/about" component={About} /></main></div>
)
export default App
// /src/index.js
// ...省略代码
import { Router } from "react-router";
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
// ...省略代码
<Router history={history}><App />
</Router>
// ...省略代码
  1. 这样我们就配置好了react-router,执行npm start命令,在浏览器中查看页面,点击Home展示Home页面,点击About展示About页面
    react路由配置成功后预览页面
接入redux

接下来,我们在项目中接入redux,首先通过npm安装以下依赖:

npm i react-redux redux redux-thunk connected-react-router
  1. 在src目录下新建modules目录,这个目录用来存放reducer相关的文件,新建counter.js和index.js
// /src/modules/counter.js
export const INCREMENT_REQUESTED = 'counter/INCREMENT_REQUESTED'
export const INCREMENT = 'counter/INCREMENT'
export const DECREMENT_REQUESTED = 'counter/DECREMENT_REQUESTED'
export const DECREMENT = 'counter/DECREMENT'const initialState = {count: 0,isIncrementing: false,isDecrementing: false
}export default (state = initialState, action) => {switch (action.type) {case INCREMENT_REQUESTED:return {...state,isIncrementing: true}case INCREMENT:return {...state,count: state.count + 1,isIncrementing: !state.isIncrementing}case DECREMENT_REQUESTED:return {...state,isDecrementing: true}case DECREMENT:return {...state,count: state.count - 1,isDecrementing: !state.isDecrementing}default:return state}
}export const increment = () => {return dispatch => {dispatch({type: INCREMENT_REQUESTED})dispatch({type: INCREMENT})}
}export const incrementAsync = () => {return dispatch => {dispatch({type: INCREMENT_REQUESTED})return setTimeout(() => {dispatch({type: INCREMENT})}, 3000)}
}export const decrement = () => {return dispatch => {dispatch({type: DECREMENT_REQUESTED})dispatch({type: DECREMENT})}
}export const decrementAsync = () => {return dispatch => {dispatch({type: DECREMENT_REQUESTED})return setTimeout(() => {dispatch({type: DECREMENT})}, 3000)}
}
// /src/modules/index.js
import { combineReducers } from 'redux'
import counter from './counter'
import { connectRouter } from 'connected-react-router'const createRootReducer = (history)=> combineReducers({counter,router: connectRouter(history)})export default createRootReducer
  1. 在src目录下新建store.js
// /src/store.js
import { createStore, applyMiddleware, compose } from 'redux'
import { routerMiddleware } from 'connected-react-router'
import thunk from 'redux-thunk'
import * as History from 'history'
import createRootReducer from './modules'export const history = History.createBrowserHistory()const initialState = {}
const enhancers = []
const middleware = [thunk, routerMiddleware(history)]if (process.env.NODE_ENV === 'development') {const devToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION__if (typeof devToolsExtension === 'function') {enhancers.push(devToolsExtension())}
}const composedEnhancers = compose(applyMiddleware(...middleware),...enhancers
)export default createStore(createRootReducer(history),initialState,composedEnhancers
)
  1. 修改下/src/index.js的内容:
// /src/index.js
// ...省略代码
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'connected-react-router'
import store, { history } from './store'
// ...省略代码
<Provider store={store}><ConnectedRouter history={history}><App /></ConnectedRouter>
</Provider>
// ...省略代码
  1. 在Home页和About页中接入redux
// 修改 /src/pages/Home/Home.js
import React from 'react'
import { push } from 'connected-react-router'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import {increment,incrementAsync,decrement,decrementAsync
} from '../../modules/counter'const Home = props => (<div><h1>Home</h1><p>Count: {props.count}</p><p><button onClick={props.increment}>Increment</button><button onClick={props.incrementAsync} disabled={props.isIncrementing}>Increment Async</button></p><p><button onClick={props.decrement}>Decrement</button><button onClick={props.decrementAsync} disabled={props.isDecrementing}>Decrement Async</button></p><p><button onClick={() => props.changePage()}>Go to about page via redux</button></p></div>
)const mapStateToProps = ({ counter }) => ({count: counter.count,isIncrementing: counter.isIncrementing,isDecrementing: counter.isDecrementing
})const mapDispatchToProps = dispatch =>bindActionCreators({increment,incrementAsync,decrement,decrementAsync,changePage: () => push('/about')},dispatch)export default connect(mapStateToProps,mapDispatchToProps
)(Home)
// 修改 /src/pages/About/About.js
import React from 'react'
import { connect } from 'react-redux'const About = (props) => (<div><h1>About Page</h1><p>这是About页面</p><p>count计数:{props.count}</p></div>
)const mapStateToProps = ({ counter }) => ({count: counter.count
})export default connect(mapStateToProps
)(About)
  1. 到此,一个react+react-router+redux的基本项目就已经配置完成了,接下来就可以做更深层次的业务开发了。
结尾

本文中没有对react-router和redux做什么原理性和概念性的介绍,纯粹作为傻瓜式的教程,由react基本项目,到接入react-router,最后接入redux完成一个基本的react全家桶项目搭建,目的是让初学者能够体验一下完整的react全家桶基本项目。在本教程中如果有什么问题,可以留言哦。
如果想要深入理解react、react-router和redux的知识,建议去官网阅读文档深入学习。
最后,在业余时间编写了一个快速构建react全家桶项目模板、vue2.x全家桶项目模板和、vue3项目模板的npm脚手架fast-project,希望大家能够下载体验,给出一些建议吶~

番外

之前的教程是搭建一个常见jsx版react项目,最近在新项目中使用了ts语言,组件编写全面拥抱了hooks,redux使用reduxjs/toolkit,而不是thunk。新的项目模板地址https://gitee.com/duchengdong/react-ts-template.git,同时也已经添加到了fast-project快速搭建项目脚手架里。

最后编辑于:2022-01-02 11:40


喜欢的朋友记得点赞、收藏、关注哦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/398159.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows Server 使用Docke部署挂载问题(安装后无限重启崩溃迁移镜像到D盘打包镜像)

文章目录 前言一、问题&#xff1a;无限重启崩溃尝试&#xff1a;权限不足&#xff1f;解决&#xff1a;用Docker-Compose安装并挂载数据卷 二、问题&#xff1a;镜像磁盘默认挂载在C盘尝试&#xff1a;通过修改Docker修改镜像磁盘到D盘解决&#xff1a;通过修改docker的settin…

深度学习 —— 个人学习笔记14(ResNet、DenseNet)

声明 本文章为个人学习使用&#xff0c;版面观感若有不适请谅解&#xff0c;文中知识仅代表个人观点&#xff0c;若出现错误&#xff0c;欢迎各位批评指正。 二十八、残差网络&#xff08; ResNet &#xff09; import torch import torchvision import time from torch impo…

Nginx代理websocket连接

文章目录 Nginx代理websocket连接1. 引言2. 为什么需要Nginx代理WebSocket3. Nginx代理WebSocket的实现步骤步骤1&#xff1a;确保Nginx支持WebSocket步骤2&#xff1a;修改Nginx配置文件步骤3&#xff1a;重启Nginx服务步骤4&#xff1a;验证配置 Nginx代理websocket连接 1. …

AI学习记录 - torch 的 matmul ,也就是点积的一些试验

有用大佬们点点赞 1、两个一维向量点积 &#xff0c;求 词A 与 词A 之间的关联度 2、两个词向量之间求关联度&#xff0c;求 : 词A 与 词A 的关联度 5 词A 与 词B 的关联度 11 词B 与 词A 的关联度 11 词B 与 词B 的关联度 25 刚刚好和矩阵乘法符合&#xff1a; 3、什么是…

Python | Leetcode Python题解之第329题矩阵中的最长递增路径

题目&#xff1a; 题解&#xff1a; class Solution:DIRS [(-1, 0), (1, 0), (0, -1), (0, 1)]def longestIncreasingPath(self, matrix: List[List[int]]) -> int:if not matrix:return 0rows, columns len(matrix), len(matrix[0])outdegrees [[0] * columns for _ in…

opencv移植

1 简介 本机环境&#xff1a;windows10 64位&#xff1b;QT&#xff1a;5.14.2 &#xff1b;本次移植不涉及源码编译&#xff0c;直接使用的编译好的源码。 2 MINGW编译环境 2.1 库文件下载 编译好的库文件下载地址&#xff1a;IJustLoveMyself/OpenCV-MinGW-Build: &#…

SPRING07_自动装配如何加强、@Autowired注解debug分析、总结

文章目录 ①. Spring启动一行代码:②. ApplicationContex增强功能③. 自动装配如何装配进来④. Autowired自动注入细节xml版⑤. Autowired注解版分析⑥. 总结一下 ①. Spring启动一行代码: ①. 创建一个IOC容器,传入容器的xml配置文件,Spring在整个创建容器的过程中全部都准备…

日期类比较大小和加减

日期比较大小 先定义一个日期类&#xff0c;这里包含年月日&#xff0c;这里头文件和源文件分离 重载符号 1.operator> 先声明函数 这里大于可以把*this> d 的情况全部列举出来 bool date::operator>(const date& d) {if (_year > d._year){return true;}e…

总要去趟沙漠吧:中卫沙坡头

周五 下班出发 西安 -> 固原 周六 疯狂的一天 陕甘宁蒙 沙坡头 集大漠、黄河、高山、绿洲为一处&#xff0c;具西北风光之雄奇&#xff0c;兼江南景色之秀美。有中国最大的天然滑沙场&#xff0c;有横跨黄河的“天下黄河第一索”&#xff0c;有黄河文化代表古老水车&#…

观测云突变告警,精准预测云原生的系统异常

背景 观测云 DataKit 是一个强大的数据采集工具&#xff0c;能够收集和监控容器化环境和 Kubernetes 集群的指标、对象和日志数据。通过灵活使用 DataKit 收集的数据&#xff0c;可以对 Kubernetes 集群进行深入的监控和分析&#xff0c;从而实现更好的运维和优化。以下是一些…

FRTIMP_YTFRB_WEB

FRTIMP_YTFRB_WEB 林业资源交易信息管理平台

Docker相关配置记录

Docker相关配置记录 换源 {"registry-mirrors": ["https://dockerhub.icu","https://docker.chenby.cn","https://docker.1panel.live","https://docker.awsl9527.cn","https://docker.anyhub.us.kg","htt…

网络通信之套接字

TCP服务端代码实现 #include<myhead.h> #define SER_POST 6666 //服务器端口 #define SER_IP "192.168.36.172"//服务器ip int main(int argc, const char *argv[]) {//1.创建套接字int sfd socket(AF_INET,SOCK_STREAM,0);//参数1&#xff1a;通信域//参数2…

零基础5分钟学会谷歌云GCP核心云架构技能 - 成本分析篇

简介&#xff1a; 欢迎来到小李哥谷歌云GCP云计算知识学习系列&#xff0c;适用于任何无云计算或者谷歌云技术背景的开发者&#xff0c;让大家零基础5分钟通过这篇文章就能完全学会谷歌云一个经典的服务开发架构方案。 我将每天介绍一个基于全球三大云计算平台&#xff08;AW…

AI赋能周界安防:智能视频分析技术构建无懈可击的安全防线

周界安全防范是保护机场、电站、油库、监狱、工业园区等关键设施免受非法入侵和破坏的重要措施。传统的周界安防手段主要依靠人员巡查和物理屏障&#xff0c;但这种方式不仅人力成本高&#xff0c;而且效率较低&#xff0c;难以满足日益复杂多变的安全需求。随着AI技术的引入&a…

windows10和linux(debian12)设置静态ip————附带详细过程

文章目录 0 背景1 linux&#xff08;debian&#xff09;1.1 查看网络配置1.2 获取ip动态分配下的配置1.3 打开网络配置文件1.4 重新启动网络服务1.5 验证设置 2 windows2.1 查看自动获取ip地址下的配置2.2 进行设置 0 背景 因为下位机只能获取固定的ip&#xff08;ip池很小&am…

QT自定义系统快捷键任务

关键代码 //自定义快捷键检测 connect(this->ui->hotkeySequenceEdit_1, &QKeySequenceEdit::keySequenceChanged,this, &HotTestWidget::setShortcut_1);// 托盘显示 trayIcon new QSystemTrayIcon(this); QPixmap pixmap("tray.png"); QIcon icon(…

【网络】IP和MAC地址的映射——ARP协议和ARP欺骗概述

目录 引言 ARP的工作机制 ARP欺骗 ARP欺骗的断网行为 ARP欺骗成为中间人 工具介绍 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 同一子网内不同主机用数据链路层的MAC地址来寻址&#xff0c;而不是子网内的私有IP&#xff08;网络层&#xff09;。数据包中的IP…

JDBC如何避免SQL注入

JDBC如何避免SQL注入 一 . 什么是SQL注入 SQL注入&#xff08;SQL Injection&#xff09;是一种代码注入技术&#xff0c;它允许攻击者将或“注入”恶意的SQL命令到后端数据库引擎执行。这些恶意的SQL命令可以执行未授权的数据库查询、修改数据、管理数据库服务器上的文件系统…

三级_网络技术_20_路由器的配置及使用

1.封禁ICMP协议&#xff0c;只转发212.78.170.166/27所在子网的所有站点的ICMP数据包&#xff0c;正确的access-list配置是()。 Router (config)#access-list 110 permit icmp 212.78.170.166 0.0.0.0 any Router (config)#access-list 110 deny icmp any any Router (confi…