当前位置: 首页 > news >正文

react项目详细搭建教程

react项目搭建create-router-dom,redux详细解说

1.搭建react脚手架

首先选择脚手架,dav-cli,create-react-app,Ant-Design-Pro-cli。脚手架即为代码层次。这里我们选用create-react-app脚手架

打开我们的cmd,window+R输入cmd进入终端,然后安装我们的脚手架
项目实例:https://gitee.com/getluoaxios/raect_dom

npm install -g create-react-app

image-20241104132008327

脚手架安装完成后,我们开始创建react新项目,稍微等一下,创建比较慢

create-react-app  名字

image-20241104132412138

进入到当前项目

cd dome-react

image-20241104132452017启动项目,下面红框包裹的为显示页面的链接

npm start

image-20241104132551933

image-20241104132619151

到此一个基本的脚手架就已经创建好了

目录:

image-20241104132735798

  1. node_modules存放项目依赖的第三方库和模块。这个目录是由 npm 自动生成的,不需要手动管理。
  2. public存放我们的静态资源
  3. src存放项目源代码的目录。这是你主要的开发目录。
  4. index入口文件,react的页面会渲染到index.html,root元素里面
  5. package.json项目的配置文件,包含项目的依赖、脚本、项目元数据等。你可以在这里定义项目的各种设置和依赖。
  6. APP.js 这是一个示例组件,作为应用的主要组件。通常,这个文件会包含应用的主要结构和逻辑。

2.React-route-dom路由使用

npm i react-router-dom
路由的基本使用
  1. 明确好界面中那块是导航区那一块是展示区
  2. 导航区使用Link不再使用a标签
<Link to="/xxxxx">Demo</Link>
  1. 展示区写Route标签进行路径的匹配
<Route path='/xxxx' component={Demo}/>
path为路径 component为展示的页面路径

<App>的最外侧包裹了一个<BrowserRouter><HashRouter>

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from "react-router-dom"const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<React.StrictMode><BrowserRouter><App/></BrowserRouter></React.StrictMode>
);reportWebVitals();

HashRouter和BrowserRouter一样,只不过HashRoute在url里是有hash值的

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {HashRouter} from "react-router-dom"const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<React.StrictMode><HashRouter><App/></HashRouter></React.StrictMode>
);reportWebVitals();
路由组件与一般组件

1.写法不同

一般组件:< Dome />

路由组件:< Route path='/xxxx' component={Demo} />

2.存放位置不同

一般组件:components

路由组件:pages,views

3.接收参数不同

一般组件:组件传什么过来,就接收什么过来

路由组件:接收固定的三个属性值

history:go: ƒ go(n)goBack: ƒ goBack()goForward: ƒ goForward()push: ƒ push(path, state)replace: ƒ replace(path, state)
location:pathname: "/about"search: ""state: undefined
match:params: {}path: "/about"url: "/about"
Switch

在React中相同路径可以加载多个组件的,假如你不想,你可以用Switch包裹一下Route,这样即使相同路径下,也只是加载最上面的组件

<Switch><Route path="/home/news" component={News}/><Route path="/home/massage" component={Message}/><Route path="/home/massage" component={Detail}/><Redirect to="/home/news"/>
</Switch>
Redirect

在react中我们想在一开始默认加载哪个组件或者路径不适配的时候我们可以用Redirect标签,可以给我们重定向加载任何一个组件,但Redirect一般出现在Route的最下面

<Switch><Route path="/home/news" component={News}/><Route path="/home/massage" component={Message}/><Redirect to="/home/news"/>
</Switch>

路由的嵌套

NavLink组件

假设现在我们需要给予选中路由一个高亮我们可以使用NavLink标签,我们可以把他单独封装成一个公用的路由组件

import React, {Component, Fragment} from "react"
import {NavLink} from 'react-router-dom'
import "./MyNavLink.css"export default class MyNavLink extends Component {render() {return (<Fragment><div className="btn-div"><NavLink activeClassName="active" className="btn-a" {...this.props}/></div></Fragment>)}
}

注意高亮默认在React-Router中是action属性

如果我们想在react项目中,写入多级路由的话,我们需要在Link,Route以及Redirect中加入父级路由

父级路由组件
import {Fragment} from "react"
import {Route, Switch, Redirect} from "react-router-dom"
import Title from "./component/Title";
import About from "./pages/About";
import Home from "./pages/Home";
import MyNavLink from "./MyNavLink";import './App.css';function App() {return (<Fragment><Title/><MyNavLink to="/about">About</MyNavLink><MyNavLink to='/home'>Home</MyNavLink><Switch><Route path="/about" component={About}/><Route path="/home" component={Home}/><Redirect to="/about"/></Switch></Fragment>);
}export default App;
子组件路由
import React, {Component, Fragment} from "react"
import {Switch, Route, Redirect} from 'react-router-dom'
import MyNavLink from "../../MyNavLink";
import Message from "./Message";
import News from "./News";export default class Home extends Component {render() {return (<Fragment><h1>我是Home</h1><br/><MyNavLink to="/home/news">News</MyNavLink><MyNavLink to="/home/massage">Massage</MyNavLink><Switch><Route path="/home/news" component={News}/><Route path="/home/massage" component={Message}/><Redirect to="/home/news"/></Switch></Fragment>)}
}
路由的模糊匹配
<Fragment><Title/><MyNavLink to="/about">About</MyNavLink><MyNavLink to='/home/a/b'>Home</MyNavLink><Switch><Route path="/about" component={About}/><Route path="/home" component={Home}/><Redirect to="/about"/></Switch>
</Fragment>

像这样的路由我们多传,虽然路径不匹配但在模糊匹配下可以让react渲染Home组件,但是不可以头路径不正确

例如:

<Fragment><Title/><MyNavLink to="/about">About</MyNavLink><MyNavLink to='/a/home'>Home</MyNavLink><Switch><Route path="/about" component={About}/><Route path="/home" component={Home}/><Redirect to="/about"/></Switch>
</Fragment>

这样前面a/home是错误的,匹配不到的

路由的严格匹配

假如现在我们不希望进行模糊匹配,严格按照路径的话我们就可以开启严格匹配模式

<Fragment><Title/><MyNavLink to="/about">About</MyNavLink><MyNavLink to='/a/home'>Home</MyNavLink><Switch><Route exact={true} path="/about" component={About}/><Route exact path="/home" component={Home}/><Redirect to="/about"/></Switch>
</Fragment>
路由的参数
传递Params参数
this.state.massageArr.map(item => {return <li key={item.id}><Link to={`/home/massage/detail/${item.id}/${item.title}`}>{item.title}</Link></li>})

我们通过数组的映射以及模版字符串的方式传递了两个Params参数

接收Params参数
<Route path="/home/massage/detail/:id/:title" component={Detail}/>
调用Params参数
export default class Detail extends Component {render() {const {id, title} = this.props.match.paramsconst findResult = data.find((_item) => {return _item.id === id})return (<Fragment><ul><li>id:{id}</li><li>title:{title}</li><li>content:{findResult.content}</li></ul></Fragment>)}
}

我们可以通过props里面的match里面封装的params里面将传递的值解构出来使用

传递Search参数
this.state.massageArr.map(item => {return <li key={item.id}><Link to={`/home/massage/detail?id=${item.id}&title=${item.title}`}>{item.title}</Link></li>})

同样我们也传递了两个Search参数,但注意Search参数不需要接收

querystring库

urlencoded编码

key=value&key=value

像这样的编码格式被称为urlencoded编码格式

利用 querystring转化格式
import qs from "querystring"qs.stringify()  将对象转化为urlencoded
qs.parse()      将urlencoded转化为js中的对象
调用Search参数
import React, {Component, Fragment} from "react"
import qs from "querystring"const data = [{id: "01", content: "你好,宁夏"},{id: "02", content: "你好,吉林"},{id: "03", content: "你好,陕西"},
]export default class Detail extends Component {render() {const {search} = this.props.locationconst {id, title} = qs.parse(search.slice(1))const findResult = data.find((_item) => {return _item.id === id})return (<Fragment><ul><li>id:{id}</li><li>title:{title}</li><li>content:{findResult.content}</li></ul></Fragment>)}
}

如果没有这个第三方库我们可以安装

npm i querystring
state参数
this.state.massageArr.map(item => {return <li key={item.id}>
<Link to={{pathname: "/home/massage/detail", state: {id: item.id, title: item.title}}}>{item.title}</Link></li>})
调用state
import React, {Component, Fragment} from "react"const data = [{id: "01", content: "你好,宁夏"},{id: "02", content: "你好,吉林"},{id: "03", content: "你好,陕西"},
]export default class Detail extends Component {render() {const {id, title} = this.props.location.stateconst findResult = data.find((_item) => {return _item.id === id})return (<Fragment><ul><li>id:{id}</li><li>title:{title}</li><li>content:{findResult.content}</li></ul></Fragment>)}
}
编程式路由导航

编程式路由导航push是压栈式的,浏览器可以回退,有保存记录。而replace是覆盖浏览器的栈顶不能回退

replace编程式路由导航
const replaceShow = (id, title) => {     this.props.history.replace(`/home/massage/detail/${id}/${title}`)}

注意只有在路由组件里面才可以使用这两个方法

push编程式路由导航
const pushShow = (id, title) => {   this.props.history.push(`/home/massage/detail/${id}/${title}`)}
withRouter

如果我们想在非路由组件里调用路由组件的方法我们就可以用withRouter

import React, {Component, Fragment} from "react"
import {withRouter} from "react-router-dom"class Title extends Component {back = () => {this.props.history.goBack()}forWord = () => {this.props.history.goForward()}render() {return (<Fragment><h2 style={{marginLeft: "50px"}}>React Router Demo</h2><button onClick={this.forWord}>前进</button><button onClick={this.back}>后退</button><hr/></Fragment>)}
}export default withRouter(Title)

注意:goBack为历史记录的后退,而goForward为前进,两个函数后可以在路由组件找到

React-Router-Dom6

安装

npm i react-router-dom@6

内置组件以及写法有些改变,函数式组件被官方明确推荐,又新增10个hooks

删除Switch,新增Routes
import {NavLink, Routes, Route} from "react-router-dom"<Routes><Route path="/about" element={<About/>}/><Route path="/home" element={<Home/>}/>
</Routes>
重定向
import {NavLink, Routes, Route} from "react-router-dom"<Routes><Route path="/about" element={<About/>}/><Route path="/home" element={<Home/>}/><Route path="/" element={<Navigate to="/about"/>}/>
</Routes>
高亮
<NavLink to="/about" className={({isActive}) => isActive ? "list-group-item active":"list-group-item"}>About</NavLink>

在react-router-dom6中可以用函数的方式返回出样式

路由表
import {NavLink, useRoutes} from "react-router-dom"
import route from "@/route/index"
const element = useRoutes(route)

我们可以通过路由表的方式生成路由

route/index

import About from "../pages/About";
import Home from "../pages/Home";
import {Navigate} from "react-router-dom";export const route = [{path: "/about",element: <About/>},{path: "/home",element: <Home/>},{path: "/",element: <Navigate to="/about"/>}
]

多级路由也可以写在路由表里,但是需要Outlet配合,类似Vue的roter-view

多级路由的路由表

import About from "../pages/About";
import Home from "../pages/Home";
import Message from "../pages/Message";
import News from "../pages/News";
import {Navigate} from "react-router-dom";export const route = [{path: "/about",element: <About/>},{path: "/home",element: <Home/>,children: [{path: "news",element: <News/>},{path: "message",element: <Message/>}]},{path: "/",element: <Navigate to="/about"/>}
]

子路由可以用children来写,类型也是数组,注意路径不要加 “/”

Outlet是子路由的出口

import React, {Fragment, useState} from "react"
import {Navigate,Outlet,NavLink} from "react-router-dom"export default function Home() {const [sum, setSum] = useState(1)return (<Fragment><h3>Home</h3>{sum === 2 ? <Navigate to="/about"/> : <h4>当前sum为{sum}</h4>}<button onClick={() => setSum(sum + 1)}>点我加一</button><NavLink to="message">message</NavLink><NavLink to='news'>news</NavLink><Outlet/></Fragment>)
}

Params参数和之前的一样传,接收参数有所改变

import React, {Fragment} from "react"
import {useParams} from "react-router-dom"export default function Detail() {const {id, title, content} = useParams()return (<Fragment><ol><li>{id}</li><li>{title}</li><li>{content}</li></ol></Fragment>)
}
Search参数接收
import React, {Fragment} from "react"
import {useSearchParams} from "react-router-dom"export default function Detail() {const [search, setSearch] = useSearchParams()const id = search.get("id")const title = search.get("title")const content = search.get("content")return (<Fragment><ol><li>{id}</li><li>{title}</li><li>{content}</li></ol><button onClick={() => {setSearch('id=008&title=哈哈&content=嘻嘻')}}>点我更新Search</button></Fragment>)
}
state参数
import React, {Fragment, useState} from "react"
import {Link, Outlet} from "react-router-dom"export default function Message() {const [message] = useState([{id: "001", title: "消息1", content: "锄禾日当午"},{id: "002", title: "消息2", content: "汗滴禾下土"},{id: "003", title: "消息3", content: "谁知盘中餐"},{id: "004", title: "消息4", content: "粒粒皆辛苦"},])return (<Fragment><ul>{message.map((_item) => {return <li key={_item.id}><Linkto="detail"state={{id: _item.id,title: _item.title,content: _item.content}}>{_item.title}</Link></li>})}</ul><hr/><Outlet/></Fragment>)
}
useLocation
import React, {Fragment} from "react"
import {useLocation} from "react-router-dom"export default function Detail() {const {state: {id, title, content}} = useLocation()return (<Fragment><ol><li>{id}</li><li>{title}</li><li>{content}</li></ol></Fragment>)
}

我们需要连续解构赋值,在useLocation中将状态state解构,再将想要的状态从stae中结构

编程式路由导航
useNavigate
import React, {Fragment, useState} from "react"
import {Link, Outlet, useNavigate} from "react-router-dom"export default function Message() {const navigate = useNavigate()function showDetail(item) {navigate("detail", {replace: false,state: {id: item.id,title: item.title,content: item.content}})}const [message] = useState([{id: "001", title: "消息1", content: "锄禾日当午"},{id: "002", title: "消息2", content: "汗滴禾下土"},{id: "003", title: "消息3", content: "谁知盘中餐"},{id: "004", title: "消息4", content: "粒粒皆辛苦"},])return (<Fragment><ul>{message.map((_item) => {return <li key={_item.id}><Linkto="detail"state={{id: _item.id,title: _item.title,content: _item.content}}>{_item.title}</Link><button onClick={() => {showDetail(_item)}}>查看详情</button></li>})}</ul><hr/><Outlet/></Fragment>)
}
前进和后退
import React, {Fragment} from "react";
import {useNavigate} from "react-router-dom"export default function Title() {const navigate = useNavigate()function back() {navigate(-1)}function forWord() {navigate(1)}return (<Fragment><h2 style={{marginLeft: "50px"}}>React Router Demo</h2><button onClick={forWord}>前进-</button><button onClick={back}>-后退</button><hr/></Fragment>)
}

Redux的基本使用

介紹:
  1. redux是一个专门用于做状态管理的JS库(不是react插件库)
  2. 它可以用在react, angular, vue等项目中, 但基本与react配合使用
  3. 作用: 集中式管理react应用中多个组件共享的状态
什么情况下需要使用redux
  1. 某个组件的状态,需要让其他组件可以随时拿到(共享)
  2. 一个组件需要改变另一个组件的状态(通信)。
  3. 总体原则:能不用就不用, 如果不用比较吃力才考虑使用

二,redux的三个核心概念

1,action
  1. 动作的对象
  2. 包含2个属性
    type:标识属性, 值为字符串, 唯一, 必要属性
    data:数据属性, 值类型任意, 可选属性
  3. 例子:{ type: ‘ADD_STUDENT’,data:{name: ‘tom’,age:18} }
2,reducer
  1. 用于初始化状态、加工状态。
  2. 加工时,根据旧的state和action, 产生新的state的纯函数。
3,store
  1. 将state、action、reducer联系在一起的对象

  2. 如何得到此对象?

  3. import {createStore} from 'redux'
    import reducer from './reducers'
    const store = createStore(reducer)
  4. 此对象的功能?

getState(): 得到state
dispatch(action): 分发action, 触发reducer调用, 产生新的state
subscribe(listener): 注册监听, 当产生了新的state时, 自动调用

redux的核心API

1.createstore

作用:创建包含指定reducer的store对象

2,store对象
  1. 作用: redux库最核心的管理对象

  2. 它内部维护着:

    state
    reducer

  3. 核心方法:

  4. store.getState()
    store.dispatch({type:‘INCREMENT’, number})
    store.subscribe(render)

3,applyMiddleware()

作用:应用上基于redux的中间件(插件库)

4,combineReducers()

作用:合并多个reducer函数

使用redux编写应用

安装:

npm install react-redux
npm install @reduxjs/toolkit
2,新建文件

src路径下,新建store文件

3,定义仓库:
新建src / store / index.js
// 定义仓库
// 引入configureStore 定义仓库
import { configureStore } from "@reduxjs/toolkit";
// 导入counterSlice
import counter from "./counterSlice";
// 导出
export const store = configureStore({// 数据处理reducer: {counter}
});
3,定义仓库:
新建src / store / index.js
/** @Author: hukai huzhengen@gmail.com* @Date: 2024-11-04 15:12:39* @LastEditors: hukai huzhengen@gmail.com* @LastEditTime: 2024-11-04 15:12:51* @FilePath: \dome-react\src\store\index.js* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE*/
// 定义仓库
// 引入configureStore 定义仓库
import { configureStore } from "@reduxjs/toolkit";
// 导入counterSlice
import counter from "./counterSlice";
// 导出
export const store = configureStore({// 数据处理reducer: {counter}
});
4,创建计数器数据,及修改数据的方法:
新建src / store / counterSlice.js
/** @Author: hukai huzhengen@gmail.com* @Date: 2024-11-04 15:13:24* @LastEditors: hukai huzhengen@gmail.com* @LastEditTime: 2024-11-04 15:13:32* @FilePath: \dome-react\src\store\counterSlice.js* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE*/
// 创建计数器切片slice
// 导入创建切片的函数
import { createSlice } from "@reduxjs/toolkit";
// 定义初始化状态
const initialState = { value: 0 };
// 创建切片
const counterSlice = createSlice({// 切片名称name: "counter",// 初始化状态initialState,// 定义处理器reducers: {// 处理加法increment: state => {state.value += 1;},// 处理减法decrement: state => {state.value -= 1;},// 处理加法addValue: (state, action) => {state.value += action.payload;}}
});// 导出动作
export const { increment, decrement, addValue } = counterSlice.actions;
// 导出处理器
export default counterSlice.reducer;
// 导出异步操作动作
export const syncAddvalue = value => dispatch => {setTimeout(() => {dispatch(addValue(value));}, 2000);
};
5.在组件中使用redux
src / APP.js 文件:

import {increment,decrement,addValue,syncAddvalue
} from "./store/counterSlice";
import { useSelector, useDispatch } from "react-redux";
const APP = () => {// 获取仓库数据const count = useSelector(state => state.counter.value);// 获取修改仓库数据的工具const dispatch = useDispatch();return (<div><p>仓库数据:{count}</p><button onClick={() => dispatch(increment())}>+1</button><button onClick={() => dispatch(decrement())}>-1</button><button onClick={() => dispatch(addValue(5))}>+5</button><button onClick={() => dispatch(syncAddvalue(10))}>两秒后+10</button></div>);
};export default APP;

效果图

image-20241104152704426


http://www.mrgr.cn/news/65975.html

相关文章:

  • 微信小程序 https://pcapi-xiaotuxian-front-devtest.itheima.net 不在以下 request 合法域名
  • 【WebRTC】WebRTC的简单使用
  • C#高级:利用反射进行同名字段的映射(类似于AutoMap)
  • 使用 pytorch 运行预训练模型的框架
  • 进度条的实现(配合make和makefile超详细)
  • Python酷库之旅-第三方库Pandas(193)
  • 深度学习入门(Python )讲义免费下载
  • 无编码器的异步电动机高性能调速系统
  • Spring Boot——日志介绍和配置
  • 线程的等待与通知
  • 分类算法——支持向量机 详解
  • Linux 实例:VNC 登录输入正确密码后无响应
  • 第七部分:1. STM32之ADC实验--单通道实验
  • opengl和opencl共享时CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR
  • 面对不同的数据源,要解决什么问题
  • AMD显卡低负载看视频掉驱动(chrome edge浏览器) 高负载玩游戏却稳定 解决方法——关闭MPO
  • 2024年华为OD机试真题-查找接口成功率最优时间段-Java-OD统一考试(E卷)
  • 容器迭代器
  • 火爆全网!南卡clip pro耳夹式耳机已售罄!它为何能这么火
  • Mybatis多数据源(一)介绍
  • 数据结构 ——— 计算链式二叉树叶子节点的个数以及计算链式二叉树的高度
  • backtrader下的轮动策略模板,附年化20.6%的策略源码。
  • 连锁餐饮企业-凡塔斯,用千里聆RPA搭建用户评价管理系统,提升门店服务满意度
  • Qt项目实战:银行利息(贷款)计算器
  • druid-multi-tenant-starter将系统改造成多租户系统如此简单
  • 企业邮箱后缀优化:提升邮件送达率的策略!