项目的整体技术架构为: react + webpack + es6 + eslint
参考网址 :https://zhuanlan.zhihu.com/p/299208218
## 一 react脚手架安装项目
1. npm i -g create-react-app // 全局安装create-react-app库,用来创建react脚手架项目的库,查看是否安装可以通过create-react-app -v 或者 npm root -a 得到一个路径,通过路径查看全局安装了什么包
2. create-react-app hello-react // 通过creat-react-app 安装脚手架 ,"hello-react"为项目名称,可以自己定义
3. cd hello-react // 进入项目文件夹
4. npm start // 启动项目
## 二 脚手架 下载下来的文件结构
public ---- 静态资源文件夹
favicon.icon ------ 网站页签图标
index.html -------- 主页面
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件
robots.txt -------- 爬虫协议文件
src ---- 源码文件夹
App.css -------- App组件的样式
App.js --------- App组件
App.test.js ---- 用于给App做测试
index.css ------ 样式
index.js ------- 入口文件
logo.svg ------- logo图
reportWebVitals.js
--- 页面性能分析文件(需要web-vitals库的支持)
setupTests.js
---- 组件单元测试的文件(需要jest-dom库的支持)
## 三 脚手架删除多余的文件
public ---- 静态资源文件夹
index.html -------- 主页面
src ---- 源码文件夹
components -------- 存放组件的文件夹
App.js --------- App组件
index.js ------- 入口文件
package.json ------- 项目的配置信息,安装包信息
package-lock.json ------- 通过npm isntall 安装package.json里所有包,并将包及它的所有依赖项保存进package-lock.json
yarn.lock ------ 通过yarn install安装package.json里所有包,并将包及它的所有依赖项保存进yarn.lock,有此文件会锁住包的版本 【需要注意一点,如果通过yarn add 来安装包,你之后通过package.json文件安装所有包的时候请使用 yarn install 】
## 四 配置antd按需映入,主题自定义,配置装饰器
1. 安装基本依赖:
antd : 蚂蚁金服UI库,
@craco/craco :通过此插件修改webpack,
@babel/plugin-proposal-decorators :配置装饰器的库,
babel-plugin-import :按需引入的库
craco-less :自定义主题需要用到类似 less-loader 提供的 less 变量覆盖功能,我们可以引入 craco-less 来帮助加载 less 样式和修改变量
安装命令:yarn add antd @craco/craco craco-less @babel/plugin-proposal-decorators babel-plugin-import
2.修改 package.json 中的 scripts
{
"scripts":{
"start": "set PORT=5000 && craco start FAST_REFRESH=true",
"build": "set GENERATE_SOURCEMAP=false && craco build",
"analyzer": "env NODE_ENV=production BUILD_ANALYZER=true yarn start",
"test": "craco test"
}
}
2.1) 修改 package.json 中的package.json -> eslintConfig ->rules ->
//配置 eslint 去掉 no-unused-vars 报错
{
// "no-": "off",
//"no-debugger":"off",
//"no-console": "off",
//"no-empty":"off",
"no-unused-vars":"off"
}
3. 在项目根目录(src同级)创建一个 craco.config.js 用于修改默认配置
4. craco.config.js中的配置
const CracoLessPlugin = require('craco-less');
module.exports = {
babel: {
plugins: [
['import', { libraryName: 'antd', style: true }], //按需引入
['@babel/plugin-proposal-decorators', { legacy: true }] // 装饰器配置
]
},
plugins: [
{
plugin: CracoLessPlugin,
options: {
// 此处根据 less-loader 版本的不同会有不同的配置,详见 less-loader 官方文档
lessLoaderOptions: {
lessOptions: {
//modifyVars: { '@primary-color': '#23442232' }, // 更改主题颜色
javascriptEnabled: true
}
}
}
}
]
};
## 一、路由的基本使用
1.明确好界面中的导航区、展示区
2.导航区的a标签改为Link标签
Demo
3.展示区写Route标签进行路径的匹配
4.的最外侧包裹了一个或
## 二、路由组件与一般组件
1.写法不同:
一般组件:
路由组件:
2.存放位置不同:
一般组件:components
路由组件:pages
3.接收到的props不同:
一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到三个固定的属性
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"
## 三、NavLink与封装NavLink
1.NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
2.Home 相当于
## 四、Switch的使用
1.通常情况下,path和component是一一对应的关系。
2.Switch可以提高路由匹配效率(单一匹配)。
## 五、解决多级路径刷新页面样式丢失的问题
1.public/index.html 中 引入样式时不写 ./ 写 / (常用)
2.public/index.html 中 引入样式时不写 ./ 写 %PUBLIC_URL% (常用)
3.使用HashRouter
## 六、路由的严格匹配与模糊匹配
1.默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)
2.开启严格匹配:
3.严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
## 七、Redirect的使用
1.一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路
由
2.具体编码:
## 八、嵌套路由
1.注册子路由时要写上父路由的path值
2.路由的匹配是按照注册路由的顺序进行的
## 九、向路由组件传递参数
1.params参数
路由链接(携带参数):详情
注册路由(声明接收):
接收参数:this.props.match.params
2.search参数
路由链接(携带参数):详情
注册路由(无需声明,正常注册即可):
接收参数:this.props.location.search
备注:获取到的search是urlencoded编码字符串,需要借助querystring解析
3.state参数
路由链接(携带参数):详情
注册路由(无需声明,正常注册即可):
接收参数:this.props.location.state
备注:刷新也可以保留住参数
## 十、编程式路由导航
借助this.prosp.history对象上的API对操作路由跳转、前进、后退
-this.props.history.push()
-this.props.history.replace()
-this.props.history.goBack()
-this.props.history.goForward()
-this.props.history.go()
## 十一、BrowserRouter与HashRouter的区别
1.底层原理不一样:
BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
HashRouter使用的是URL的哈希值。
2.path表现形式不一样
BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
HashRouter的路径包含#,例如:localhost:3000/#/demo/test
3.刷新后对路由state参数的影响
(1).BrowserRouter没有任何影响,因为state保存在history对象中。
(2).HashRouter刷新后会导致路由state参数的丢失!!!
4.备注:HashRouter可以用于解决一些路径错误相关的问题。
## 十二、withRouter的使用
1. 是一般组件装换成路由组件,withRouter是一个函数
2. 使用:
import {withRouter} from 'react-router-dom'
export default withRouter(<一般组件名称>)
3. 包装之后的组件里会有同路由组件一样多了很多路由专属的API可用(this.props)
// 路由使用得基本结构 to,path和component是一一对应的关系
// 路由器的两种表现形式 BrowserRouter 和 HashRouter
tom
bill
alex
// Switch可以提高路由匹配效率,匹配到路由就不会继续匹配下去
//exact 精准匹配路由
## 路由传参有三种方法
1.params参数
路由链接(携带参数):详情
注册路由(声明接收):
接收参数:this.props.match.params
2.search参数
路由链接(携带参数):详情
注册路由(无需声明,正常注册即可):
接收参数:this.props.location.search
备注:获取到的search是urlencoded编码字符串,需要借助querystring解析
3.state参数
路由链接(携带参数):详情
注册路由(无需声明,正常注册即可):
接收参数:this.props.location.state
备注:刷新也可以保留住参数(只的是BrowserRouter路由)
// 安装 redux , react-redux
yarn add redux react-redux // 默认是安装在生产环境(-S)
yarn add redux-thunk // 中间件 允许异步action,就是指action的值为函数
redux主要由三部分组成:store,reducer,action
store是一个对象,它有四个主要的方法(dispatch,subscribe,getState,replaceReducer)
reducer
1. 创建一个store,应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中,
store可以通过createStore()方法创建,接受三个参数,经过combineReducers合并的reducer和 state的初始状态以及改变dispatch的中间件,后两个参数并不是必须的。store的主要作用是将action和 reducer联系起来并改变state
import { createStore, combineReducers } from "redux"
import aboutReducer from "../reducers/aboutReducer" // reducers 处理简单逻辑返回的是一个函数
import homeReducer from "../reducers/homeReducer" // reducers 处理简单逻辑返回的是一个函数
const allReducers = combineReducers({
aboutData: aboutReducer,
homeData: homeReducer
})
export default createStore(allReducers)
2. 容器组件需要包裹UI组件,UI组件和容器组件通过react-redux中的connect()相互连接,
UI组件可以直接通过this.props直接获取数据, connect()接受两个参数并且还是函数,
第一个函数(mapStateToProps)返回的是一个对象,对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value,该函数用于传递状态
第二个函数(mapDispatchToProps)函数返回的是一个对象,返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value,该函数用于传递操作状态的方法
connect(
state => {
return { modal: state }
},
dispatch => ({
jia: number => dispatch({ type: 'jia', data: number })
})
)(About) // About是UI组
3. React-Redux 提供 组件,能够使整个app访问到Redux store中的数据
ReactDOM.render(
,
document.getElementById('root')
)
##总结
1. 创建一个store.js文件, 引入reducers, 例子 :
// store.js 该文件专门用于暴露一个store对象,整个应用只有一个store对象
//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware} from 'redux'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//暴露store
export default createStore(reducer,applyMiddleware(thunk))
2. 在入口文件引入 store.js,
// index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
import {Provider} from 'react-redux'
ReactDOM.render(
/* 此处需要用Provider包裹App,目的是让App所有的后代容器组件都能接收到store */
,
document.getElementById('root')
)
3. 在UI组件中,此时UI组件命名为Home
import React, { Component } from 'react'
//引入connect用于连接UI组件与redux
import {connect} from 'react-redux'
//定义UI组件
class Home extends Component {
render(){
return .....
}
}
//使用connect()()创建并暴露一个Count的容器组件
export default connect(
state => ({
count:state.count,
personCount:state.persons.length
}),
{increment,decrement,incrementAsync}
)(Home)
(1). Hook是React 16.8.0版本增加的新特性/新语法
(2). 可以让你在函数组件中使用 state 以及其他的 React 特性
三个常用的Hook : State Hook 、Effect Hook 、Ref Hook
## State Hook
(1). State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作
(2). 语法: const [xxx, setXxx] = React.useState(initValue)
(3). useState()说明:
参数: 第一次初始化指定的值在内部作缓存
返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数
(4). setXxx()2种写法:
setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
const [count,setCount] = React.useState(init)
count : 初始变量
setCount :更新变量
写法1:setCount(count+1)
写法2 : setCount(count => count+1)
init : 初始值
## Effect Hook
(1). Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
(2). React中的副作用操作:
发ajax请求数据获取
设置订阅 / 启动定时器
手动更改真实DOM
(3). 语法和说明:
useEffect(() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
}
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行
(4). 可以把 useEffect Hook 看做如下三个函数的组合
componentDidMount()
componentDidUpdate()
componentWillUnmount()
React.useEffect(()=>{}) // 相当于类组件中 componentDidMount , componentWillUpdate
React.useEffect(()=>{},[]) // 相当于 componentDidMount
React.useEffect(()=>{},[Name]) // 当setName的时候,会触发
React.useEffect(()=>{ return ()=>{} },[Name]) // 返回函数的函数相当于componentWillUnmount
## Ref Hook
(1). Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据
(2). 语法: const refContainer = useRef()
(3). 作用:保存标签对象,功能与React.createRef()一样
例子:
function Demo(){
const myRef = React.useRef()
function show(){
alert(myRef.current.value)
}
return (
)
}