相信不少剛入坑React的小夥伴們有一個一樣的疑惑,因爲React相關庫不斷的再進行版本迭代,網上不少之前的技術分享變得再也不適用。好比react-touter2
與react-router4
在寫法上存在很多區別,之前的調用方法將沒法使得項目正常工做。我最近用React全家桶在構建一個spa,因爲官方文檔給的比較繁瑣,使用相似react-cli
的腳手架工具會使你的理解停留在表面,能用單反相機就不用傻瓜相機~~最好仍是本身動手豐衣足食。在這裏但願能用通俗易懂的方式來講一下如何快速構建spa。(PS:此文旨在讓你們少走彎路,所以在項目結構上力求全而簡)css
在此以前你先須要懂得基本的 nodejs 操做與 ES2015 語法。
經過npm
安裝webpack:npm install webpack
,而後用node運行配配置文件(這裏並不是絕對,也能夠直接在cmd裏運行,但不推薦)html
首先給出項目結構:vue
--component //組件文件夾 ㄴ--hello.jsx //組件jsx --more-component //嵌套組件能夠放在次級目錄 --js ㄴ--common.js //本身經常使用的js方法, --css ㄴ--hello.css //每一個組件對應一個css文件,便於管理 --img --route ㄴ--router.jsx //路由配置組件 --store //redux相關 ㄴ--action.js //狀態發起動做方法 ㄴ--reducer.js //接受動做後改變狀態 entry.jsx //打包入口 temp.html //打包模板html webpack.config.js //webpack配置
項目結構根據我的習慣能夠修改,但原則上要保持條理清晰,有時候還要根據項目結構修改webpack配置等。node
接下來配置webpack
,同時npm
安裝所須要的 loader
。webpack
相關配置請參考webpack中文文檔。本章很少作贅述。
給出一個簡單配置:
webpack.config.jsreact
const webpack = require("webpack"); const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const compiler = webpack({ entry: "./entry.jsx", output:{ path: path.resolve(__dirname, "./dist"), filename:"code.min.js" }, module:{ rules:[ { test:/\.css$/, include:[path.resolve(__dirname, "./")], loader:"style-loader!css-loader" }, { test:/\.js$/, include:[path.resolve(__dirname, "./")], loader:"babel-loader", options: { presets: ['es2015',"stage-0"] } }, { test:/\.jsx$/, include:[path.resolve(__dirname, "./")], loader:"babel-loader", options: { presets: ['es2015',"stage-0","react"] } }, { test: /\.(png|jpeg|jpg)$/, include:[path.resolve(__dirname, "./img")], loader:'file-loader?name=img/[name]-[hash].[ext]' } ] }, plugins: [ new HtmlWebpackPlugin({ template:'./temp.html', filename:'./spa.html', inject:'body' }) ] }); const watching = compiler.watch({ aggregateTimeout: 300, poll: undefined }, (err, stats) => { if (err || stats.hasErrors())console.log(stats.compilation.errors); else{console.log('success')} })
當編寫好webpack.config.js
文件後,咱們只須要用node運行它,那麼當咱們的react項目改變時會自行編譯到一個自動生成的dist
文件夾裏(建議必定開啓監聽文件改變編譯,而不是每次改變後手動運行webpack.config.js
,由於那樣會很慢!)webpack
作好了這些準備工做,接下來正式進入 React
世界:
entry.jsgit
import React from 'react' import { render } from 'react-dom' import { createStore } from 'redux' import todoApp from './store/reducers' import Main from './route/router.jsx' let store = createStore(todoApp) render( <Main store={store} />, document.body )
上面import
的模塊請npm
安裝,咱們在entry
裏僅僅建立一個狀態管理的store
對象,而且將router.jsx
的路由模塊渲染到body
中,reducers
是redux
中具體須要更改哪些狀態的js文件,在creatStore
裏綁定。(關於redux的更多使用方法及理解須要詳細具體講解,涉及篇幅較大,本文暫不涉及,有興趣能夠看文檔redux中文文檔,我會整理後再單獨章節分享)github
接下來咱們將編寫路由組件
router.jsxweb
import React from 'react' import { HashRouter as Router,Route } from 'react-router-dom' import { Provider } from 'react-redux' import Hello from '../component/hello.jsx'; class Main extends React.Component { render(){ const { store } = this.props return ( <Router hashType="noslash"> <Provider store={store}> <Route render={({ location }) => { return( <div key={location.pathname} name={location.pathname}> <Route location={location} path="/hello" component={Hello}/> </div> ) }}/> </Provider> </Router> ) } } export default Main ;
這與react-router2
有一些差異,原來的方法已經再也不使用,在react-router4
中HashRouter
或BrowserRouter
組件從react-redux-dom
中引入。vuex
關於業務組件的編寫,相信你們都很熟悉,即便之前使用es5
開發的小夥伴也應該能很快上手
hello.jsx
import '../css/xxx.css'; import React from 'react'; import { connect } from 'react-redux'; import * as action from '../store/actions'; class Hello extends React.Component{ constructor(props){ super(props) this.state={...} } componentDidMount(){ this.props.dispatch(action.hi()) } render() { const { name } = this.props return ( <div>{name}</div> ) } } export default connect(state => state)(Hello)
在這個組件裏,咱們將redux
中管理的state
和觸發狀態更改的dispatch
方法經過connect
綁定在了props
中,能夠隨時調用,同時該組件將監聽redux
中state
的變化實時更新數據。
咱們須要改變redux
狀態時所觸發的動做
action.js
export const hi = () => { return { type:'hi', ...//其餘你須要的屬性 } }
根據redux
要求,這裏的type
屬性是必須的,不能用別的字段名,不然運行時瀏覽器會報type
不存在。
接收action
後執行狀態改變的文件就是
reducers.js
import { combineReducers } from 'redux' const name = (state='', action) => { switch (action.type) { case 'hi': return "hello world!" default : return state } } const todoApp = combineReducers({ name, //more state }) export default todoApp;
reducer
首先用action
中傳入的type
屬性來判斷咱們要作的是哪一種操做,而後再根據傳入的其餘屬性當作參數作你想要的改變,最後返回一個{name : ...}
的對象,而後全部相似的對象經過combineReducers
合併爲一個總狀態對象暴露給組件訪問。
當以上文件利用webpack編譯打包好之後,一個最簡單的react全家桶spa就完成了(雖然只包含一個組件)。
在實際的使用過程當中,須要更多的庫來使咱們的應用更強大且美觀。好比路由過分動畫react-addons-css-transition-group
,redux異步更改state數據redux-thunk
,Ajax的兼容shimwhatwg-fetch
,移動端滾動iscroll
等等。
關於react-router4
與redux
的詳細用法仍是建議要靜下心來理解文檔,這樣才能在變化無窮的開發需求中運用自如。(我以前也用過vuex
,感受相比之下redux
文檔稍顯繁瑣,vuex
文檔看了很容易就理解上手了)
若是感興趣能夠訪問個人成熟項目源碼React醫療類移動app --Github,歡迎各位多多指教,多多star ^_^