前言:此文需要有一定react,redux基礎,具體學習資料請科學上網。
|-src //開發
|----assets //css,img資源
|----unit.js //公用方法
|----routers //路由配置
|----containers //業務邏輯頁面
|----component //通用元件
複製程式碼
啟動
# install dependencies
npm install
# serve with hot reload at localhost:8080
npm start
# build for production with minification
npm run build
複製程式碼
使用create-react-app腳手架
配合antd元件實現的管理系統demo, 線上地址
開發前反思
1. 按需載入
webpack的import
動態載入的模組的函式,import(引數),引數為模組地址。
注意:import
後會返回一個promise物件。
import('/components/chart').then(mud => {
dosomething(mod)
});
複製程式碼
本demo構建了非同步載入元件Bundle,具體程式碼請見
class Bundle extends Component {
constructor(props) {
super(props);
this.state = {
mod: null
};
}
unmount = false
componentDidMount = () => {
// 載入元件時,開啟全域性loading
this.props.dispatch(loading(true))
this.load(this.props)
}
componentWillUnmount = () => {
this.unmount = true
}
componentWillReceiveProps(nextProps) {
if (nextProps.load !== this.props.load) {
this.load(nextProps)
}
}
load(props) {
if (this.state.mod) {
return true
}
//注意這裡,使用Promise物件; mod.default匯出預設
props.load().then((mod) => {
if (this.unmount) {
// 離開元件時,不非同步執行setState
this.props.dispatch(loading(false))
return false
}
this.setState({
mod: mod.default ? mod.default : mod
}, _ => {
// 元件載入完畢,關閉loading
this.props.dispatch(loading(false))
});
});
}
render() {
return this.state.mod ? this.props.children(this.state.mod) : null;
}
}
複製程式碼
具體使用
<Bundle load={() => import('路徑')}>
{Comp => {
return Comp ? <Comp /> : <div>載入中...</div>
}}
</Bundle>
複製程式碼
2. 全域性loading
配合redux,dispatch => reducer更新 => mapstate更新,在根元件進行loading的渲染
詳細請見本demo地址 src/routers/router.js——render函式
3. 配置路由物件
專案佈局如下
本demo使用的是router4,官方文件演示為單行Route(如vue種的router),未有統一配置物件。 管理系統基本圍繞著content進行業務開發,構建通用配置有助於開發 構建router.config.jsconst routers = [
{
menuName: '主頁',
menuIco: 'home',
component: 'home/home.js', // 主頁
path: '/admin/home' // 主頁
},
{
menuName: '使用者',
menuIco: 'user',
children: [
{
menuName: '使用者列表',
component: 'user/list.js', // 主頁
path: '/admin/user/list' // 主頁
}
]
},
{
menuName: '多級選單',
menuIco: 'setting',
children: [
{
menuName: '多級選單2',
children: [
{
menuName: '選單',
component: 'user/list.js', // 主頁
path: '/admin/user/list3' // 主頁
}
]
}
]
},
{
menuName: '關於我',
menuIco: 'smile-o',
component: 'about/about.js', // 主頁
path: '/admin/about' // 主頁
}
]
複製程式碼
實現思路,最外層佈局為Admin,content被Admin包裹,那麼可以利用this.props.children
,把內容打入content中。(利用bundle元件非同步載入後塞入元件進行渲染)
<Admin>
<Content { ...this.props } breadcrumb={this.state.breadcrumb}>
{this.props.children}
</Content>
</Admin>
複製程式碼
// Content元件內部
render() {
return (
<div>
{this.props.children}
</div>
)
}
// 本demo實現,詳見src/routers/router.js
<Route
path="/admin"
render={item => (
<Admin {...item} { ...this.props }>
{initRouters.map(el => this.deepItem(el, { ...this.props, ...item}))}
</Admin>
)}
/>
複製程式碼
4. 配置通用reducer
多人配合開發,一些業務場景的元件需要狀提升(不理解狀態提升的同學,請科學上網)
import otherReducers from './otherReducers'
const App = combineReducers({
rootReducers,
...otherReducers // 其他需要增加的reducers
})
複製程式碼
5. 登陸驗證
利用withRouter
函式,頁面進行路由跳轉時觸發該函式
const newWithRouter = withRouter(props => {
// ....
})
複製程式碼
若未登入,則返回
return <Redirect to="/login" />
複製程式碼
6. 路由攔截
同上,根據路由配置與許可權,返回相應的選單或遮蔽
return <Redirect to={其他} />
複製程式碼
7 其他配置
7-1. 自定義樣式
// 修改webpack.config.dev.js 和 webpack.config-prod.js 配置檔案
{
test: /\.(css|less)$/,
// 匹配src的都自動載入css-module
include: [/src/],
exclude: [/theme/],
use: [
require.resolve('style-loader'), {
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
modules: true, // 新增對css modules的支援
localIdentName: '[path]___[name]__[local]___[hash:base64:5]'
}
}, {
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebookincubator/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%', 'last 4 versions', 'Firefox ESR', 'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009'
})
]
}
}, {
loader: require.resolve('less-loader') // compiles Less to CSS
}
]
}, {
// 不匹配node_modules,theme的都不能自動載入css-module
test: /\.(css|less)$/,
include: [/node_modules/,/theme/],
use: [
{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
importLoaders: 1
}
}, {
loader: require.resolve('less-loader') // compiles Less to CSS
}
]
},
複製程式碼
使用: 在App.js中直接匯入
import './assets/theme/App.less'
複製程式碼
7-2. 熱更新
步驟一:
// 安裝react-hot-loader
npm install --save-dev react-hot-loader
複製程式碼
步驟二:
在webpack.config.js 的 entry 值里加上 react-hot-loader/patch
步驟三:
webpackDevServer.config.js中hot設定為true
步驟四: 在webpack.config.dev.js中在babel-loader中plugins加入react-hot-loader/babel
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
// This is a feature of `babel-loader` for webpack (not Babel itself). It
// enables caching results in ./node_modules/.cache/babel-loader/ directory for
// faster rebuilds.
cacheDirectory: true,
plugins: [
'react-hot-loader/babel'
]
}
},
複製程式碼
步驟五:
重寫index.js,App掛載
import { AppContainer } from 'react-hot-loader'
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component></Component>
</AppContainer>,
document.getElementById('root')
)
}
render(App)
if(module.hot) {
module.hot.accept('./App',() => {
render(App);
});
}
複製程式碼
7-3. 本地瀏覽
直接在package.json中加入
homepage:'.'
複製程式碼
後記:使用react與vue的感悟
react是函數語言程式設計,程式碼難度、學習曲度、裝逼指數,社群生態多樣性相比vue更高一點。
vue提供了大量的指令降低了開發難度,詳細完善的文件,上手更快。
react提供較少的api,相比vue的指令,業務場景的功能需要自己實現,難度更高一點
vue適合中小型專案,單兵、少量人員配合快速開發
react適合大型專案,多人協作
github: https://github.com/treasureDouDou