大家好,欢迎来到IT知识分享网。
1、基础介绍
- 本文采用的模块之家的实例项目为模板,采用react+react-router-dom+redux+axios+antd+js-cookie+less等技术栈来实现。
- 本文假设你对react已经有基本了解。
- react官方文档
- react-router官方文档
2、创建项目
- create-react-app react_pc_demo
- cd react_pc_demo
- npm (run) start
3、暴露配置文件
- react项目默认是隐藏配置文件的。
- 本项目选择暴露配置文件的方式
npm run eject
暴露配置文件(操作的时候本地不能有修改的文件、否则会报错This git repository has untracked files or uncommitted changes
)
4、配置别名
- 在
webpack.config.js
的alias
配置中增加如下配置
alias: {
'@': paths.appSrc
}
复制代码
- 修改引用方式,重启(修改配置文件必须重启才能生效)验证配置是否成功
// import logo from './logo.svg';
// import './App.css';
import logo from '@/logo.svg';
import '@/App.css';
复制代码
5、项目结构规划
- 可以修改成自己熟悉的项目结构
+-- src/ ---核心代码目录
| +-- api ---api配置
| +-- assets ---静态资源文件夹
| +-- components ---功能组件
| +-- layout ---布局组件(用于划分页面布局的组件)
| +-- pages ---页面组件(具有路由)
| +-- router ---路由配置文件
| +-- styles ---样式配置文件
| +-- utils ---辅助函数
| --- index.js ---项目入口文件
复制代码
- 后续可根据需求进行扩展和模块划分
6、less配置
- 本文采用less对css进行预处理
npm install -S less less-loader / cnpm i -S less less-loader
复制代码
- 在
webpack.config.js
的style files regexes
配置中增加如下配置
const cssRegex = /\.css|less$/; 修改为=> const cssRegex = /\.css|less$/
复制代码
- 在
webpack.config.js
的loaders
配置中增加如下配置
{
loader: require.resolve('less-loader')
}
复制代码
- 修改css文件为less文件、重启服务查看效果
7、配置路由
- cnpm i -S react-router-dom // react-router-dom依赖包含react-router
- 新建路由文件,在router文件下新建index.js文件
import React from "react"
import { HashRouter, Route, Switch, Redirect } from "react-router-dom"
import Home from '@/pages/home'
export default () => (
<HashRouter>
<Switch>
<Route path="/home" component={Home}></Route>
<Redirect exact from="/" to="/home" />
</Switch>
</HashRouter>
)
复制代码
- 在项目入口文件index.js中使用router
import Router from "@/router"
ReactDOM.render(<Router />, document.getElementById('root'));
复制代码
- 路由介绍
- HashRouter/BrowserRouter 定义路由方式Hash/或者Location
- Switch路由切换组件,多个Route时用Switch包裹,否则会报警告
- Route路由
- Redirect路由重定向
- exact路由绝对匹配
8、状态管理(redux)
- cnpm i -S redux react-redux redux-thunk // redux-thunk => action异步处理
- 新建store文件夹,新建state,actions,reducers,actionTypes
state: 初始化数据
import { getUserInfo } from '@/utils/store'
export default {
userReducer: {
userName: getUserInfo()
},
orderReducer: {
orderType: 'order',
completed: 'false',
num: 0
}
}
复制代码
actionTypes: 集中管理action操作类型
export const USER_LOGIN = 'USER_LOGIN'
export const ADD_ORDER_NUM = 'ADD_ORDER_NUM'
export const USER_LOGOUT = 'USER_LOGOUT'
复制代码
actions: 修改state必须通过action
import { USER_LOGIN, ADD_ORDER_NUM, USER_LOGOUT } from './actionTypes'
export function userLogin(payload) {
return {
type: USER_LOGIN,
payload
}
}
export function logout() {
return {
type: USER_LOGOUT
}
}
export function addOrderNum() {
return {
type: ADD_ORDER_NUM
}
}
复制代码
reducers: 数据处理
import { combineReducers } from 'redux'
import { USER_LOGIN, ADD_ORDER_NUM, USER_LOGOUT } from './actionTypes'
import initialState from './state'
import { setUserInfo, removeUserInfo } from '@/utils/store'
let userReducer = (state = initialState.userReducer, action) => {
switch (action.type) {
case USER_LOGIN:
setUserInfo(action.payload)
return {
...state,
userName: action.payload
}
case USER_LOGOUT:
removeUserInfo()
return {
...state,
userName: null
}
default:
return state
}
}
let orderReducer = (state = initialState.orderReducer, action) => {
switch (action.type) {
case ADD_ORDER_NUM:
return {
...state,
num: ++state.num
}
default:
return state
}
}
export default combineReducers({
userReducer,
orderReducer,
})
复制代码
- 在页面中使用
- 修改index.js文件
import { createStore, applyMiddleware } from 'redux'
import reducers from './reducers'
import initialState from './state'
import thunk from "redux-thunk"
const enhancer = applyMiddleware(thunk)
export default createStore(
reducers,
initialState,
enhancer
)
复制代码
- 高阶组件connect
// 此处仅仅只是演示页面
import React, { Component } from 'react';
import PropsTypes from 'prop-types' // cnpm i -S prop-types
import { connect } from 'react-redux' // connect高阶组件
import { addOrderNum } from '@/store/actions' // 引入action
class OrderNum extends Component {
static PropsTypes = { // 定义数据类型
orderType: PropsTypes.string,
num: PropsTypes.number.isRequired,
completed: PropsTypes.bool,
addOrderNum: PropsTypes.func.isRequired
}
render() {
return (
<div className="order_component">
<p>orderType: {this.props.orderType}</p>
<p>orderNum: {this.props.num}</p>
<p>completed: {this.props.completed}</p>
<button onClick={this.props.addOrderNum}>add order number</button> // 使用action
</div>
);
}
}
const mapStateToProps = (state, ownProps) => ({ // 当前组件需要使用的state数据
orderType: state.orderReducer.orderType,
completed: state.orderReducer.completed,
num: state.orderReducer.num
})
const mapDispatchToProps = { // 当前组件需要反馈的action
addOrderNum
}
export default connect(mapStateToProps, mapDispatchToProps)(OrderNum)
复制代码
9、中间件middleware
- 安装,上面已安装(可忽略)
cnpm i -S redux-thunk // 增强action异步处理
复制代码
- 使用
// 修改store
import { createStore, applyMiddleware } from 'redux'
import reducers from './reducers'
import initialState from './state'
import thunk from "redux-thunk"
const enhancer = applyMiddleware(thunk)
export default createStore(
reducers,
initialState,
enhancer
)
复制代码
10、添加布局layout和子路由
- 在layout下则增加DefaultLayout组件,新增公共头部底部组件
- 在router下增加module文件夹,新增frontRouter组件,在DefaultLayout使用此模块路由。
11、ui(antd)的使用
- 安装依赖
cnpm i -S antd
复制代码
- 配置, style为css和true区别你是否需要使用
babel-plugin-import
引入你的样式(在非按需引用时你需要将.css改为.less),它的好处在于可以显著减少包大小
在babel-loader的plugins中增加如下配置
['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }]
或者
['import', { libraryName: 'antd', libraryDirectory: 'es', style: true }]
复制代码
- 重启后使用
import { Button } from 'antd'
复制代码
ps
,当你在使用style: true时可能遇到以下错误,Inline JavaScript is not enabled. Is it set in your options?
,解决办法,在less-loader
的options
增加以下配置javascriptEnabled: true
Failed to compile.
./node_modules/_antd@3.12.1@antd/es/button/style/index.less (./node_modules/_css-loader@1.0.0@css-loader??ref--6-oneOf-3-1!./node_modules/_postcss-loader@3.0.0@postcss-loader/src??postcss!./node_modules/_less-loader@4.1.0@less-loader/dist/cjs.js!./node_modules/_antd@3.12.1@antd/es/button/style/index.less)
// https://github.com/ant-design/ant-motion/issues/44
.bezierEasingMixin();
^
Inline JavaScript is not enabled. Is it set in your options?
in D:\user\80002912\桌面\my_project\react_pc_demo\node_modules\_antd@3.12.1@antd\es\style\color\bezierEasing.less (line 110, column 0)
复制代码
- 修改如下配置
code
{
loader: require.resolve('less-loader'),
options: {
javascriptEnabled: true
}
}
复制代码
12、前后端交互
- 安装依赖(本项目使用的是axios)
cnpm i -S axios qs
复制代码
- 二次封装axios,详见api下index.js和fetch.js文件
api
fetch.js 二次封装axios
index.js 集中管理api,可根据需要进行模块化划分,在组件中按需引用即可
复制代码
13、react-router
路由跳转
- 路由组件的跳转
this.props.history.push('/path')
复制代码
- 外部组件的跳转
- 使用
Link
跳转
<Link to="/path">go to other page</Link>
复制代码
- 路由组件传递
如test为home组件的子组件
<test history={this.props.history} />
在test中
this.props.history.push('/path')
复制代码
- 通过
context
共享
home组件
getChildContext() { // 通过context申明共享数据
return {
history: createHashHistory()
}
}
static childContextTypes = { // 申明共享数据类型
history: PropTypes.object
}
在test中
static contextTypes = { // 申明需要使用的共享数据及类型
history: PropTypes.object
}
在'render'中通过'this.context.history'使用
复制代码
- 直接引用
history
import createHashHistory from 'history/createHashHistory'
const history = createHashHistory()
在组件内部
history.push('/path')
复制代码
14、组件异步加载(code split)
react-router 4.0
以上版本
- 借助
babel-plugin-syntax-dynamic-import
+react-loadable
实现按需加载
cnpm i -D babel-plugin-syntax-dynamic-import
cnpm i -S react-loadable
复制代码
- 组件内使用,核心代码如下,将
import Home from '@/pages/home'
改为使用Loadable()
的方式const Home = Loadable({loader: () => import('@/pages/home'), loading})
import Loadable from 'react-loadable'
import loading from '@/components/common/loading' // 自定义的loading组件
// import Home from '@/pages/home';
// import Login from '@/pages/login';
// import Error_404 from '@/pages/error404';
// import DefaultLayout from '@/layout/default';
const Home = Loadable({loader: () => import('@/pages/home'), loading});
const Login = Loadable({loader: () => import('@/pages/login'), loading});
const Error_404 = Loadable({loader: () => import('@/pages/error404'), loading});
const DefaultLayout = Loadable({loader: () => import('@/layout/default'), loading});
复制代码
react-router 4.0
以下版本
- 借助
require.ensure()
,如:
const Home = (location, cb) => {
require.ensure([], require => {
cb(null, require('./component/home').default);
}, 'home');
}
或者借助包装类'Bundle Loader'
npm i --save bundle-loader
const Home = (props) => (
<Bundle load={(cb) => {
require.ensure([], require => {
cb(require('./component/home'));
});
}}>
{(Home) => <Home {...props}/>}
</Bundle>
);
复制代码
- 使用
import()
,如:
const Home = (props) => (
<Bundle load={() => import('./component/home')}>
{(Home) => <Home {...props}/>}
</Bundle>
);
复制代码
15、总结
- 本文已模板之家项目为实现,介绍了开发过程中的各种配置。
- 后期在开发时,可能对代码部分略有修改,但思路不变。
- 本文的实例已放到马云上,并持续同步更新。
- 目前已实现的功能有首页、登录页、购物车等
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/14550.html