React项目搭建
# React项目搭建
1、react提供了一个用于创建react项目的脚手架库: create-react-app,使用脚手架搭建项目可以节省时间,它包含了搭建项目所需要的基本的配置(语法检查、jsx编译等等)。
1、全局安装脚手架:npm i -g create-react-app
2、使用脚手架创建项目:create-react-app zl-react
3、创建完成后:
npm start
Starts the development server.
npm run build
Bundles the app into static files for production.
npm test
Starts the test runner.
npm run eject
Removes this tool and copies build dependencies, configuration files
and scripts into the app directory. If you do this, you can’t go back!
4、创建完成后项目结构:
public ---- 静态资源文件夹
favicon.icon ------ 网站页签图标
index.html -------- 主页面
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件
robots.txt -------- 爬虫协议文件
src ------ 源码文件夹
App.css ----------- App组件的样式
App.js ------------ App组件
App.commonJS-test1.js ------- 用于给App做测试
index.css --------- 样式
index.js ---------- 入口文件
logo.svg ---------- logo图
reportWebVitals.js
--- 页面性能分析文件(需要web-vitals库的支持)
setupTests.js
---- 组件单元测试的文件(需要jest-dom库的支持)
# React项目文件分析
1、入口文件分析(index.js)
import React from 'react';
import ReactDOM from 'react-dom/client';
//import ReactDOM from 'react-dom'
import './index.css';
import App from './App';
//root是public文件下的index.html的root节点
1、ReactDOM.render(<App/>,document.getElementById('root')) //注:ReactDom的创建方式不同
//react-dom V18.0.0只有可以使用的创建方式
2、const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<App/>
);
2、App.jsx 文件
//引入React核心库
import {Component} from 'react'
//引入需要展示的组件
import Hello from './components/Hello'
//将类式组件暴露出去
export default class App extends Component{
render(){
return (
<div>
<Hello/>
</div>
)
}
}
3、setupProxy.js代理文件配置,代理相当于中间服务器,主要的目的是解决浏览器的同源策略产生的跨域问题。
const proxy = require('http-proxy-middleware')
module.exports = function(app) {
app.use(
proxy('/api1', {
target: 'http://localhost:5000', //转发的目标服务器
changeOrigin: true, //解决服务器对请求的识别问题
pathRewrite: {'^/api1': ''} //是否重新确定路径,将/api1去掉
}),
proxy('/api2', {
target: 'http://localhost:5001',
changeOrigin: true,
pathRewrite: {'^/api2': ''}
}),
)
}
注: 如果不需要转发至不同的域,可以在package.json文件中进行如下的配置
"proxy": "http://localhost:5000"
# React路由使用
路由主要是通过使用浏览器自身的history对象,监听访问路径的变化,展示和操作页面(通常使用history.js来操作history对象)
1、安装、引入
npm install react-router-dom
import {
BrowserRouter,
Route,
Link
} from 'react-router-dom'
react-router-dom 提供了 BrowserRouter 和 HashRouter 路由。
这两个路由都会为你创建一个专门的 history 对象。
一般来说,如果你有一个响应请求的服务器,则你应该使用 BrowserRouter ,
如果你使用的是静态文件的服务器,则应该使用 HashRouter(会在路由的路径上增加#,并且#之后的内容不会转发至服务器)
1、React中,使用 Link 或者 NavLink 进行路径的切换,相当于html的a标签,向history栈进行push操作。
<Link className="test" to="/about">About</Link>
<Link className="test" to="/home">Home</Link>
<NavLink activeClassName="demo" className="test" to="/about">About</NavLink>
<NavLink activeClassName="demo" className="test" to="/home">Home</NavLink>
注:NavLink相比于Link多了activeClassName,activeStyle等属性,便于标签在被选中的时候增加样式。
2、注册路由
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
3、使用link标签的时候,需要BrowserRouter 或者 HashRouter进行包裹。
为了方便,我们一般可以直接加在入口文件的app之上(index.js)。
<BrowserRouter>
<App/>
</BrowserRouter>
4、switch标签的使用
未使用前:以下的场景会将/about路由匹配Test组件
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/about" component={Test}/>
使用后:路由匹配到后就不会接着往下匹配,所有/about路由匹配到的是About组件
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Route path="/about" component={Test}/>{/* 改行匹配是失效的 */}
</Switch>
5、<Redirect> 重定向标签
将导航到一个新的地址。这个新的地址会覆盖 history 栈中的当前地址,类似服务器端的重定向。
<Redirect to="/about"/>
2、多级路由和路由传参
1、多级路由刷新产生的样式丢失问题
由于刷新导致请求的地址发生变化,可能会使主页面引入的外部文件请求地址出错。
解决方案:
|<link rel="stylesheet" href="/css/bootstrap.css"> //去除href后面 './'中的 '.'
|<link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css"> //使用%PUBLIC_URL%,定位至public文件夹(仅React)
|使用HashRouter
2、路由的模糊匹配和精准匹配:
<Link className="test" to="/about/a/b/c">About</Link>
<Route path="/about" component={About}/>
比如以上的路由可以匹配的path:/about,/about/a,/about/a/b,/about/a/b/c;
注意要匹配完整的path,不能是/about 或者/about/x
<Route path="/about" exact={true} component={About}/>
使用精准匹配后,不能够模糊匹配,但是开启之后,多级路由会出现问题。路由开启严格模式后,此路由的二级三级路由都会失效
4、路由传递参数--params参数
<Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>test</Link>
注册路由时,声明接收params参数
<Route path="/home/message/detail/:id/:title" component={Detail}/>
获取传递过来的params参数
const {id,title} = this.props.match.params
5、路由传递参数--search参数
<Link to={`/home/message/detail?id=${msgObj.id}&title=${msgObj.title}`}>test</Link>
注册路由时,如果携带的是search参数,无需声明接收,直接注册即可
<Route path="/home/message/detail" component={Detail}/>
获取传递过来的search参数
import qs from 'querystring'
const {search} = this.props.location
//去掉?并处理参数
const {id,title} = qs.parse(search.slice(1))
6、路由传递参数--state参数
<Link to={{pathname:'/home/message/detail',state:{id:'009',title:msgObj.title}}}>test</Link>
注册路由时,如果携带的是state参数,无需声明接收,直接注册即可
<Route path="/home/message/detail" component={Detail}/>
获取传递过来的state参数
const {id,title} = this.props.location.state
7、编程式路由(常用方法)
this.props.history.push('/home/XXX')
this.props.history.replace('/home/XXX')
this.props.history.goBack()
this.props.history.goForward();
history 对象通常会具有以下属性和方法:
length - (number 类型) history 堆栈的条目数
action - (string 类型) 当前的操作(PUSH, REPLACE, POP)
location - (object 类型) 当前的位置。location 会具有以下属性:
pathname - (string 类型) URL 路径
search - (string 类型) URL 中的查询字符串
hash - (string 类型) URL 的哈希片段
state - (object 类型) 提供给例如使用 push(path, state) 操作将 location 放入堆栈时的特定 location 状态。只在浏览器和内存历史中可用。
push(path, [state]) - (function 类型) 在 history 堆栈添加一个新条目
replace(path, [state]) - (function 类型) 替换在 history 堆栈中的当前条目
go(n) - (function 类型) 将 history 堆栈中的指针调整 n
goBack() - (function 类型) 等同于 go(-1)
goForward() - (function 类型) 等同于 go(1)
block(prompt) - (function 类型) 阻止跳转。
8、withRouter
当路由渲染时, withRouter 会将已经更新的 match , location 和 history 属性传递给被包裹的组件。
给非路由组件的props绑定match , location 和 history 属性。