項目地址 :https://github.com/kliuj/reac...html
下載完項目npm install
而後npm run dev
便可
基於 react react-router redux
的項目,主要是爲了學習實戰react
。數據都是固定的,從餓了麼接口臨時抓的,模擬了一個0-100ms
的異步數據延遲,感謝餓了麼。react
如下內容是項目開發的過程和一些思考,按照這個過程至少能保證明現一個相對完整的react
全家桶項目webpack
react
文檔:http://reactjs.cn/react/docs/...react-router
文檔地址 :https://reacttraining.com/rea...react-router
中文版參考:http://www.uprogrammer.cn/rea...redux
文檔參考:http://redux.js.org/redux
中文文檔:http://cn.redux.js.org/
git
創建項目目錄,安裝package.json,配置webpack.config
作好基礎依賴工做,摘自package.json的一部份內容github
"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個模塊的設計:web
1:後臺接口通訊層:
model.js
主要處理統一接口的請求發送和回調,放在一塊兒更有利於後期維護,也增長可閱讀性npm
//接口對應的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
主要處理頁面之間的跳轉返回,增長更多的自主性和擴展性json
// 自動存儲瀏覽記錄 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
主要用來定義一些公用的模塊方法redux
//放置公用函數 export function showToast(){ ... }
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-... 有簡單的介紹。promise
這個是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組件裏面監聽了滾動事件進行自動加載的處理
使用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狀態的數據,每次數據改變都會下發給全部接收的組件