react+react-router+react-redux全家桶小專案開發過程分享
react-ele-webapp
http://www.jianshu.com/p/a96f6e0b66d1?utm_source=tuicool&utm_medium=referral
run
下載完專案npm install
然後npm run dev
即可
基於 react react-router redux
的專案,主要是為了學習實戰react
。資料都是固定的,從餓了麼介面臨時抓的,模擬了一個0-100ms
的非同步資料延遲,感謝餓了麼。
以下內容是專案開發的過程和一些思考,按照這個過程至少能保證實現一個相對完整的react
全家桶專案
內容參考
搭建專案:
建立專案目錄,安裝package.json,配置webpack.config
做好基礎依賴工作,摘自package.json的一部分內容
"devDependencies": {
"babel-core": "^6.23.1",
"babel-loader": "^6.4.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.23.0",
"html-webpack-plugin": "^2.28.0",
"jshint": "^2.9.4",
"jshint-loader": "^0.8.4",
"react": "^15.2.0" ,
"react-dom": "^15.2.0",
"react-router": "^2.0.0",
"redux": "^3.6.0",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.4.1"
} //JAVASCRIPT
專案模組結構組織一些基礎工作
開始進行開發一個專案除了技術選型之外,還有許多基礎東西要先設計好,一個好的組織設計要可以為以後的提高工作效率。我這方面還有很多欠缺,目前主要考慮了3個模組的設計:
1:後臺介面通訊層:
model.js
主要處理統一介面的請求傳送和回撥,放在一起更有利於後期維護,也增加可閱讀性
//介面對應的url,這裡只做演示 const uris = { index_entry : fetchData.index_entry, hot_search_words : fetchData.hot_search_words } //介面呼叫層 export default function send(url,postData,successCallback,errCallback){ //模擬延遲,假介面 let promise = new Promise(function(resolve,reject){ setTimeout(function(){ resolve(fetchData[url]) },Math.random()*100) }) promise.then(function(data){ successCallback(data) }) }
2:本地資料快取維護:
baseStore.js
主要處理頁面之間的跳轉返回,增加更多的自主性和擴充套件性
// 自動儲存瀏覽記錄 export function saveFrom(prop) { let name = prop.pagename, transit = prop.location, qhfrom = transit.query.qhfrom ,//預設全部返回首頁 para = transit.query.para ? JSON.parse(transit.query.para) : ''; if(!qhfrom) return false; let paths = localStorage.getItem("FromUrlStore") ? JSON.parse(localStorage.getItem("FromUrlStore")) : {}; if (localStorage) { paths[name] = { 'name':qhfrom,//儲存來源頁面 'para':para //儲存來源頁面的引數 } localStorage.setItem("FromUrlStore", JSON.stringify(paths)); } } //儲存頁面的來源,統一管理
3:公共方法的處理:
baseFun.js
主要用來定義一些公用的模組方法
//放置公用函式 export function showToast(){ ... }
使用react-router初始化頁面
import React from 'react'
import { render } from 'react-dom'
import { Router, Route, Link,hashHistory ,IndexRedirect,IndexRoute} from 'react-router'
import Home from './components/home.jsx'
import Discover from './components/discover.jsx'
const App = React.createClass({
render() {
return (
<div>
<footer>
<Link to="/home">外賣</Link>
<Link to="/discover?qhfrom=home">發現</Link>
</footer>
{this.props.children}
</div>
)
}
})
const route = (
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Home} />
<Route path="home" component={Home} />
<Route path="discover" component={Discover} />
</Route>
</Router>
)
render(route, document.getElementById("app"))
程式碼簡單介紹:
因為沒有後臺,採用的 hashHistory
(hash
路由),關於hash
路由可以參考:https://github.com/kliuj/spa-routers 有簡單的介紹。
這個是router的跳轉 <Link to="/home">外賣</Link>
這個是載入子路由元件 {this.props.children}
這個是預設的跳轉頁面 <IndexRoute component={Home} />
處理首頁的滾動列表
首頁主要分成了4個元件
底部導航 + 滾動列表 + 單個產品 + 首頁搜尋框
滾動列表封裝了一個簡單的元件
<List list={Pro} //每個產品item元件 pagename={'home'} //跳轉產品列表的上級頁面 用來處理返回 data={this.state.productList} //需要渲染的資料 onScroll = {this.getMore.bind(this)}//滾動載入函式 /> 在scrollList元件裡面監聽了滾動事件進行自動載入的處理
react-redux 處理登入和登出
使用redux的原因:使用者資訊和登入是兩個不同的元件,也沒有父子級的關係,但是需要進行資料狀態共享和相互影響。詳細資訊可以看上面的官方文件,我這裡就簡單說一下我這個專案的應用。
定義常量
actionTypes.js
//登入成功 export const LOG_SUCCESS = 'LOG_SUCCESS' //正在登入 export const LOG_ING = 'LOG_ING' //登出登入 export const LOG_OUT = 'LOG_OUT' //主要是統一儲存狀態對應的名稱
定義具體的觸發操作
actions/login.js
//登出 同步 export function log_out (){ return { type:actionTypes.LOG_OUT } } //登入 非同步 export function log_in (obj){ return dispatch=>{ //pending 正在進行登入的狀態 dispatch({type:actionTypes.LOG_ING}) //開始傳送非同步請求登入 new Promise((resolve,reject)=>{ ... }).then(res=>{ dispatch(res) }) } } //非同步狀態需要使用中介軟體
處理資料
reducers/login.js
export default function(state = initialData,action){ switch(action.type){ case actionTypes.LOG_SUCCESS: return { loginstate:1, username:action.username } break case actionTypes.LOG_ING: return{ loginstate:-1, username:'正在登入' } case actionTypes.LOG_OUT: return initialData break default : return initialData } }
使用中介軟體建立store層
store/store.js
import {createStore, applyMiddleware} from 'redux' import thunk from 'redux-thunk' //合併的多個reducer,解耦 import rootReducer from '../reducers/index.js' const middlewares = [thunk] const createStoreWithMiddleware = applyMiddleware(...middlewares)(createStore) export default function configureStore(initialState){ return createStoreWithMiddleware(rootReducer,initialState) }
在路由層引入
import {Provider} from 'react-redux' const store = configureStore() const route = ( <Provider store={store}> <Router history={hashHistory}> ... </Router> </Provider> )
元件裡面使用
```
import { connect } from 'react-redux'
import {log_out} from '../../actions/login.js' //操作
...
...
function mapStateToProps(userinfo){
let {login} = userinfo //這個是返回的所有reducer,我們只用當前需要的,參考 reducers/index.js 內容
return login
}
export default connect(mapStateToProps)(UserInfo)
//這個時候就可以在當前元件狀態的 this.props 獲取到這個 login 資料,
//操作的時候
const {dispatch} = this.props;
dispatch(log_out())
//這時候就可以操作redux狀態的資料,每次資料改變都會下發給所有接收的元件
```