近期react最振奮人心的更新hooks迅速流行於社群,工作之餘,出於對新技術的興趣和探索精神,搭建了這個簡單的腳手架工具,方便後續的迭代和小夥伴之間的交流。
原材料:
1、react16.7.0-alpha.2
2、webpack4.26.1 + webpack-cli3.1.2
3、react-router-dom4.3.1
相信很多小夥伴已經在社群看到很多有關以上各個技術的最新進展和分享了,但是對於想輕鬆上手,卻又缺乏一定的腳手架配置經驗的小夥伴依然無所適從,想實踐起來又容易踩到各種坑。
於是,我先踩為敬了。
我們一起學貓叫,一起喵喵喵喵喵~
本腳手架主要採用較新的庫搭建,請注意node版本也要跟上哦~
目錄結構
請忽略package資料夾,它是存放打包檔案的
一、入口開始
import { render } from 'react-dom';
import { applyMiddleware, createStore} from 'redux'
import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
import promise from 'redux-promise-middleware'
import Routers from './router'
import reducers from './reducers'
const middleware = applyMiddleware(promise(), thunk)
const store = createStore(reducers, middleware)
render(
<Provider store={store}>
<Routers />
</Provider>,
document.getElementById("app")
)
複製程式碼
(⊙o⊙)…好像沒啥好說的額,重點在Router,reducers這裡。我們只要知道,這裡是打包/程式執行的切入點就可以了。
二、承上,Router
import React from 'react'
import { connect } from 'react-redux'
import { replace } from 'react-router-redux'
import { BrowserRouter as Router, Route, Link, Redirect, Switch } from 'react-router-dom';
import AsyncComponent from 'components/AsyncComponent';
const NotMatch = AsyncComponent(() => import('components/NotMatch'));
const App = AsyncComponent(() => import('pages/app'));
@connect(null, {replace})
export default class RootRouter extends React.Component{
render(){
const props = this.props;
//如果沒有許可權,在此進行判定並replace跳轉
return (
<Router>
<div>
<ul>
<li><Link to='/'>首頁</Link></li>
<li><Link to='/about'>關於</Link></li>
<li><Link to='/topics'>主題列表</Link></li>
</ul>
<hr/>
<Switch>
<Route exact path="/" render={() => <Redirect to='/login'/>}/>
<Route path="/login" component={App} />
<Route path="/about" component={App} />
<Route path="/topics" component={App} />
<Route component={NotMatch} />
</Switch>
</div>
</Router>
)
}
}
複製程式碼
react-router4.x後,Broswerhistory已經從react-router中移除,此時需要使用Broswerhistory時,需要安裝react-router-dom,這時候,路由看起來更像是一個常見的react元件了。之前的版本打包需要非同步載入路由模組使用webpack的require.ensure方法,比如
const App = (location, cb) => {
require.ensure([], require => {
cb(null, require('./components/App'))
})
}
複製程式碼
再配合 getComponent屬性:
<Route path="/" getComponent={ App }/>
而現在getComponent也沒啦,咋整?
寫個方法吧,沒錯,就是路由檔案中的AsyncComponent方法:
AsyncComponent.jsx
import React, { Component } from "react";
export default importComponent => class AsyncComponent extends Component {
state = {
component: null
}
async componentDidMount(){
const {default: component} = await importComponent();
this.setState({component});
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : null;
}
};
複製程式碼
其實這也是一個元件,只不過是該元件載入完成後,再匯入真正需要載入的元件。此時還要配合webpack打包配置的output.chunkFilename屬性,稍後會貼出程式碼。
@connect(null, {replace})是類的裝飾器,不瞭解的可以單獨百度一下。
三、啟下,component
再往後就很清晰了,./components/App下的元件就是我們的業務元件了。
直接看截圖中的SubCom.jsx元件程式碼
import React, { useState, useEffect, useRef } from 'react';
const effect = count => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
return () => document.title = 'clear'
};
export default ({change}) => {
let [count, setCount] = useState(2);
const click = e => {
count++;
change(count);
setCount(count);
};
useEffect(effect.bind(null, count));
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return <React.Fragment>
<div onClick={click}>
{count}
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</div>
<p>你穩定不點個贊再走嗎?</p>
</React.Fragment>
}
複製程式碼
我們期待的hooks登場啦啦啦~~~但今天不是講hooks的,社群講它的很多很詳細,這裡直接用了。順便把useRef,React.Fragment等用法也貼了上來。
同時為了方便直接開展業務,reducer,action,介面格式,axios二次封裝以及示例函式均已寫好,因為有程式碼潔癖,所以資料夾佈局以及重複邏輯均做了處理。
配置檔案也比較基本,為了加快編譯速度,特意新增了動態連結庫的配置,這裡強調一下:除了babel-loader,並沒有配置css有關的loader,url-loader,file-loader以及樣式抽離、壓縮的外掛,小夥伴們根據自己的需要新增配置即可。程式碼太多就不貼了。
以前有面試官問我怎樣使用ES6的語法書寫配置檔案,當時確實沒有思考過這個問題,直接告訴她我對這個不感興趣~~~不過今天的配置檔案用的ES6來寫的,配置檔名稱後加上.babel字尾即可......就是這麼簡單。 完了,再發一張我的貓吧