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) start3、暴露配置文件 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:user80002912桌面my_project
eact_pc_demo
ode_modules\_antd@3.12.1@antdesstylecolorezierEasing.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> ); 本文转载于网络,以资检录
我将决定学习此框架