React開發管理後臺實踐2---React基本內容學習
在這一節裡,我們以一個醫生管理自己的患者為例,向大家介紹React基本內容。包括React、Redux和Router,以及基於Ajax的前後端聯調功能。
頁面元件顯示
假設我們頁面顯示如下內容,標題是“患者管理”,第一個列表標題為“高血壓患者”,然後是高血壓患者列表,第二個列表標題為“糖尿病患者”,然後是糖尿病患者列表。
在程式入口點src/App.js中新增如下程式碼:
import React, { Component } from 'react';
import HighBlood from './HighBlood';
import Diabete from './Diabete';
const diabetes = [
{'patientId': 201, 'patientName': 'D201'},
{'patientId': 202, 'patientName': 'D202'},
{'patientId': 203, 'patientName': 'D203'},
{'patientId': 204, 'patientName': 'D204'}
];
class App extends Component {
render() {
const title = '患者管理';
return (
<div>
<h1>{title}</h1>
<HighBlood></HighBlood>
<Diabete patients={diabetes}></Diabete>
</div>
);
}
}
//......
其中HighBlood和Diabete是兩個子元件,分別定義在src/HighBlood.js和src/Diabete.js中。我們將糖尿病患者,我們使用全域性變數陣列diabetes來儲存,並通過patients屬性傳遞給Diabete子元件。而高血壓患者列表資料將定義在HighBlood元件內部的state中。
我們首先來看高血壓元件src/HighBlood.js:
import React, { Component } from 'react';
class HighBlood extends Component {
constructor(props) {
super(props);
this.state = {
ps: [
{'patientId': 101, 'patientName': 'p101'},
{'patientId': 102, 'patientName': 'p102'},
{'patientId': 103, 'patientName': 'p103'},
{'patientId': 104, 'patientName': 'p104'}
]
};
}
addPatient = () => {
console.log('新增高血壓患者');
this.setState({
ps: [...this.state.ps, {'patientId': 105, 'patientName': 'p105!'}
]
});
}
render() {
const content = '高血壓患者';
return (
<div>
<h2>{content}</h2>
<button onClick={this.addPatient}>新增患者</button>
<ul>
{this.state.ps.map(v => {
return <li key={v.patientId}>{v.patientName}</li>
})}
</ul>
</div>
);
}
}
export default HighBlood;
我們通過建構函式中定義state中具有一個ps屬性,是一個物件陣列,儲存患者列表資料。與糖尿病患者元件不同,採用state定義的屬性可以動態更加,也就是介面中的“新增患者”按鈕是可以使用的。
接著我們定義了一個“新增患者”按鈕,並定義單擊響應函式為addPatient,注意這裡addPatient函式定義時只能採用箭頭函式形式,否則會報找不到this的錯誤(當然也可以有其他方法來避免這個錯誤,大家只需要掌握這種就可以了)。
接下來我們來看render函式,其首先顯示了列表標題。然後定義ul元素,state中的陣列ps呼叫map函式,在其內部用箭頭函式定義了對陣列每個元素的操作。這裡是利用陣列元素的值建立一個li元素。
如果我們點選新增按鈕,就會執行addPatient函式,在這個函式中,我們通過this.setState來重新給ps陣列賦值,在賦值時我們先用展開運算子,將原陣列內容展開為列表,然後再新增新元素。
接下來我們來看Diabete元件,這個元件與HighBlood的唯一區別就是患者列表資料是通過父元件以屬性方式傳遞過來的。這裡需要注意的一點,由於患者列表是父元件通過屬性傳遞過來的,因此患者列表是不能改變的,所以這裡的新增按鈕是不起作用的,程式碼如下所示:
import React, { Component } from 'react';
class Diabete extends Component {
addPatient = () => {
console.log('新增糖尿病患者');
}
componentWillMount() {
console.log('生命週期函式:componentWillMount');
}
componentDidMount() {
console.log('生命週期函式:componentDidMount ^_^');
}
render() {
const content = '糖尿病患者';
return (
<div>
<h2>{content}</h2>
<button onClick={this.addPatient}>新增患者</button>
<ul>
{this.props.patients.map(v => {
return <li key={v.patientId}>{v.patientName}</li>;
})}
</ul>
</div>
);
}
}
export default Diabete;
Redux初步
利用Redux管理患教文章數量
首先安裝redux為:
npm install redux --save
我們首先定義事件型別,在患教文章管理中,我們有兩個事件,一個是新增患教文章,一個刪除患教文章,我們在src/action_type.js定義這兩個事件:
export const ADD_ARTICLE = 'AddArticle'
export const REMOVE_ARTICLE = 'RemoveArticle'
接著我們定義產生這兩個事件的方法,在src/action.js檔案中定義:
import { ADD_ARTICLE, REMOVE_ARTICLE } from './action_type'
export function createAddArticleAction() {
let action = { type: ADD_ARTICLE }
return action
}
export function createRemoveArticleAction() {
let action = { type: REMOVE_ARTICLE }
return action
}
接著我們定義reducer來處理這兩個事件,如src/reducer.js檔案所示:
// Reducer定義
import { ADD_ARTICLE, REMOVE_ARTICLE } from './action_type'
export function articleReducer(state={}, action) {
console.log(`articleReducer type=${action.type}...`)
switch (action.type) {
case ADD_ARTICLE:
if (!state.articleNum) {
state.articleNum = 0
}
state.articleNum += 1
console.log(`articleReducer articleNum=${state.articleNum}...`)
return state
case REMOVE_ARTICLE:
if (!state.articleNum) {
state.articleNum = 0
}
state.articleNum -= 1
return state
default:
return state
}
}
我們首先在src/index.js檔案中引入redux的store物件,並進行監聽:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux'
import './index.css'
import App from './App'
import registerServiceWorker from './registerServiceWorker'
import { articleReducer } from './reducer'
const store = createStore(articleReducer)
function render() {
ReactDOM.render(<App store={store} />, document.getElementById('root'))
}
render()
registerServiceWorker()
store.subscribe(render)
最後我們在頁面中新增增加文章和刪除文章按鈕,並新增相應的事件處理函式,如下所示:
import React, { Component } from 'react'
import HighBlood from './HighBlood'
import Diabete from './Diabete'
import { createAddArticleAction, createRemoveArticleAction } from './action'
const diabetes = [
{'patientId': 201, 'patientName': 'D201'},
{'patientId': 202, 'patientName': 'D202'},
{'patientId': 203, 'patientName': 'D203'},
{'patientId': 204, 'patientName': 'D204'}
]
class App extends Component {
addArticle = () => {
console.log('App.addArticle')
const store = this.props.store
store.dispatch(createAddArticleAction())
}
removeArticle = () => {
console.log('App.removeArticle')
const store = this.props.store
store.dispatch(createRemoveArticleAction())
}
render() {
const title = '患者管理'
const store = this.props.store.getState()
let num = 0
if (store.articleNum) {
num = store.articleNum
}
return (
<div>
<h1>{title}</h1>
<span>文章數:{num}</span><br />
<button onClick={this.addArticle}>新增文章</button><br />
<button onClick={this.removeArticle}>刪除文章</button>
<HighBlood></HighBlood>
<Diabete patients={diabetes}></Diabete>
</div>
)
}
}
export default App
由上面的程式碼可以看到,在render方法中,我們通過屬性獲取store中的state,可以得到文章數量並顯示在介面中。在新增或刪除文章時,我們生成相應的事件,通過store.dispatch方法,最終呼叫reducer中相應的處理函式來進行處理。
為了使程式更加優雅,我們可以將事件生成函式引用移出App元件。我們在index.js中引入事件,並以屬性的形式傳遞給App元件,如下所示:
......
import { articleReducer } from './reducer'
import { createAddArticleAction, createRemoveArticleAction } from './action'
const store = createStore(articleReducer)
function render() {
ReactDOM.render(<App store={store} createAddArticleAction={createAddArticleAction} createRemoveArticleAction={createRemoveArticleAction} />, document.getElementById('root'))
}
......
我們在App元件中,可以通過屬性來使用這些函式,如下所示:
......
class App extends Component {
addArticle = () => {
console.log('App.addArticle')
const store = this.props.store
const createAddArticleAction = this.props.createAddArticleAction
store.dispatch(createAddArticleAction())
}
removeArticle = () => {
console.log('App.removeArticle')
const store = this.props.store
const createRemoveArticleAction = this.props.createRemoveArticleAction
store.dispatch(createRemoveArticleAction())
}
render() {
......
Redux處理非同步任務
我們首先來安裝一個三方庫:
npm install redux-thunk --save
開啟非同步中介軟體,在index.js檔案中引入thunk和中介軟體:
......
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import './index.css'
import App from './App'
......
const store = createStore(articleReducer, applyMiddleware(thunk))
function render() {
ReactDOM.render(<App store={store} createAddArticleAction={createAddArticleAction} createRemoveArticleAction={createRemoveArticleAction} createAddArticleAsyncAction={createAddArticleAsyncAction} />, document.getElementById('root'))
}
......
我們在第3行引入redux的applyMiddleware,在第4行引入非同步處理中介軟體thunk,在建立store時加入中介軟體初始化,並將非同步事件createAddArticleAsyncAction以屬性形式傳遞給App元件。
在App元件中,我們新增一個非同步新增按鈕,如下所示:
addArticleAsync = () => {
console.log('App.addArticleAsync...........')
const store = this.props.store
const createAddArticleAsyncAction = this.props.createAddArticleAsyncAction
store.dispatch(createAddArticleAsyncAction())
}
其實這部分程式碼與同步事件基本沒有什麼區別。
在src/action.js檔案中新增非同步事件,如下所示:
export function createAddArticleAsyncAction() {
return dispatch => {
setTimeout( () => { dispatch(createAddArticleAction()) }, 2000)
}
}
在非同步處理函式中,我們返回的是一個箭頭函式,引數為dispatch,其功能就是呼叫延時函式,在2秒後呼叫dispatch函式,執行真正的新增操作。
Redux開發除錯工具
為開發Redux應用方便,可以安裝redux的除錯工具,開啟Chrome的“更多工具”=》“擴充套件程式”,點選左上角選單,點選最下面“開啟Chrome網上應用商店”,在其中搜尋Redux DevTools,安裝該外掛。
啟用Redux DevTools需要在src/index.js檔案中新增如下程式碼:
......
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
......
const store = createStore(articleReducer,
compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f=>f
)
)
......
首先引入redux中的compose函式,接著在建立store時使用compose函式啟用開發除錯工具。
使用react-redux
直接使用redux還是相對比較煩瑣,我們可以使用react-redux來簡化這一過程,通過如下命令安裝:
npm install react-redux --save
我們在src/index.js檔案中引入react-redux的Provider元件,程式碼如下所示:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import { Provider } from 'react-redux'
import './index.css'
import App from './App'
import registerServiceWorker from './registerServiceWorker'
import { articleReducer } from './reducer'
import { createAddArticleAction, createRemoveArticleAction, createAddArticleAsyncAction } from './action'
const store = createStore(articleReducer,
compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f=>f
)
)
ReactDOM.render(
(
<Provider store={store}>
<App />
</Provider>
),
document.getElementById('root'))
registerServiceWorker()
這裡最大的變化是我們不需要Render函式和監聽了,同時store只需要作為屬性傳遞給Provider元件即可。
接下來我們需要改造App元件,將src/App.js改為如下形式:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { createAddArticleAction, createRemoveArticleAction, createAddArticleAsyncAction } from './action'
import HighBlood from './HighBlood'
import Diabete from './Diabete'
const diabetes = [
{'patientId': 201, 'patientName': 'D201'},
{'patientId': 202, 'patientName': 'D202'},
{'patientId': 203, 'patientName': 'D203'},
{'patientId': 204, 'patientName': 'D204'}
]
class App extends Component {
render() {
const title = '患者管理'
const store = this.props.store
const state = store.getState()
return (
<div>
<h1>{title}</h1>
<span>文章數:{this.props.articleNum}</span><br />
<button onClick={this.props.createAddArticleAction}>新增文章</button><br />
<button onClick={this.props.createRemoveArticleAction}>刪除文章</button>
<button onClick={this.props.createAddArticleAsyncAction}>非同步新增</button>
<HighBlood></HighBlood>
<Diabete patients={diabetes}></Diabete>
</div>
)
}
}
const mapStatetoProps = (state) => {
return { articleNum: state.articleNum }
}
const actionCreators = { createAddArticleAction, createRemoveArticleAction, createAddArticleAsyncAction }
App = connect(mapStatetoProps, actionCreators)(App)
export default App
大家可以看到,我們在App元件中,就不需要使用dispatch了,直接使用屬性中對應的方法即可。在最後面,我們用mapStatetoProps這時狀態中變數對應於本元件中的屬性,actionCreators定義事件生成函式為元件屬性。
接下來我們安裝babel外掛:
npm install babel-plugin-transform-decorators-legacy --save
然後在package.json檔案的babel定義部分新增外掛,如下所示:
"babel": {
"presets": [
"react-app"
],
"plugins": [
"transform-decorators-legacy"
]
},
如上所示,加入了transform-decorators-legacy外掛。
接著我們就可以簡化App元件中的程式碼了,如下所示:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { createAddArticleAction, createRemoveArticleAction, createAddArticleAsyncAction } from './action'
import HighBlood from './HighBlood'
import Diabete from './Diabete'
const diabetes = [
{'patientId': 201, 'patientName': 'D201'},
{'patientId': 202, 'patientName': 'D202'},
{'patientId': 203, 'patientName': 'D203'},
{'patientId': 204, 'patientName': 'D204'}
]
@connect(
(state) => {
return { articleNum: state.articleNum, state: state }
},
{ createAddArticleAction, createRemoveArticleAction, createAddArticleAsyncAction }
)
class App extends Component {
render() {
const title = '患者管理 v0.0.2'
console.log(`num=${this.props.articleNum}`)
return (
<div>
<h1>{title}</h1>
<span>文章數:{this.props.articleNum} vs {this.props.state.articleNum}</span><br />
<button onClick={this.props.createAddArticleAction}>新增文章</button><br />
<button onClick={this.props.createRemoveArticleAction}>刪除文章</button>
<button onClick={this.props.createAddArticleAsyncAction}>非同步新增</button>
<HighBlood></HighBlood>
<Diabete patients={diabetes}></Diabete>
</div>
)
}
}
export default App
通過使用@connect語法,可以精簡react-redux繫結程式碼,該函式有兩個引數,第一個引數是屬性中需要state的屬性,第二個引數是需要自動dispatch的事件。
使用Router
Router 4是最新版本的路由元件,可以在Web、ReactNative上統一使用。首先是先安裝庫:
npm install react-router-dom --save
我們首先在src/index.js檔案中定義Router,如下所示:
......
import { Provider } from 'react-redux'
import { BrowserRouter, Route, Link } from 'react-router-dom'
import './index.css'
......
ReactDOM.render(
(
<Provider store={store}>
<BrowserRouter>
<div>
<ul>
<li><Link to='/'>患者列表</Link></li>
<li><Link to='/patientDetail'>患者詳情</Link></li>
<li><Link to='/articleList'>文章列表</Link></li>
</ul>
<Route path='/' exact component={App}></Route>
<Route path='/patientDetail' component={PatientDetail}></Route>
<Route path='/articleList' component={ArticleList}></Route>
</div>
</BrowserRouter>
</Provider>
),
document.getElementById('root')
)
......
在第2行引入router中常用元件。在頁面上方定義三個導航選單,分別對應三個頁面。通過不同的URL顯示不同的元件。
然後再分別定義PatientDetail元件:
import React, { Component } from 'react';
class PatientDetail extends Component {
render() {
return <h1>患者詳情</h1>
}
}
export default PatientDetail
再定義文章列表頁面:
import React, { Component } from 'react';
class ArticleList extends Component {
render() {
return <h1>文章列表</h1>
}
}
export default ArticleList
這樣就組成了一個最簡單的多頁面應用。由此可見Router功能的強大。在後面我們要用到的開源後臺應用,就是採用這一基本原理來實現的。
迷你完整應用
我們要實現的功能是使用者在訪問任意一個頁面時,如果沒有登入userId<=0,則跳轉到登入頁面,如果已經登入,顯示使用者名稱和登出按鈕,點選登出按鈕回到登入頁面。在登入頁面點選登入按鈕,進入患者列表頁面,如果訪問不存在的頁面,顯示404頁面。我們還有一個關於我們頁面,使用者不登入也可以看。
為了開發這一應用,我們現在有兩個主要的功能,一個是登入相關邏輯,另一個是患者列表頁面邏輯。為此我們分別設計Auth.redux.js和Home.redux.js兩個reducer。因為在我們的體系架構下,只能有一個reducer,所以我們需要使用combineReducers元件。我們新建src/reducers.js檔案,內容如下所示:
// 合併所有reducers
import { combineReducers } from 'redux'
import { authReducer } from './Auth.redux'
import { articleReducer } from './Home.redux'
export default combineReducers({
authReducer,
articleReducer
})
我們在程式入口處的src/index.js中,生成全域性store時,引用這個合併後的reducers,程式碼如下所示:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import { Provider } from 'react-redux'
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom'
import './index.css'
import registerServiceWorker from './registerServiceWorker'
import reducers from './reducers'
import App from './App'
import Login from './Login'
import NotFound from './NotFound'
const store = createStore(reducers,
compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f=>f
)
)
ReactDOM.render(
(
<Provider store={store}>
<BrowserRouter>
<Switch>
<Route path='/login' component={Login}></Route>
<Route path='/home' component={App}></Route>
<Route path='/not-found' component={NotFound}></Route>
<Redirect to='/not-found'></Redirect>
</Switch>
</BrowserRouter>
</Provider>
),
document.getElementById('root')
)
registerServiceWorker()
在上面的程式碼中,我們在createStore時傳入的是我們剛剛建立的統一的reducer,其中包括articleReducer和authReducer兩個元素。接下來路由方面,我們定義了登入頁Login,首頁為App元件,404頁面,並定義如果沒有任何路由命中,則直接轉到404頁面。
我們先來看登入頁面src/Login.js定義:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { Redirect } from 'react-router-dom'
import { login } from './Auth.redux'
@connect(
(state) => {
return {
userId: state.authReducer.userId
}
},
{ login }
)
class Login extends Component {
constructor(props) {
super(props)
}
render() {
const redirectToPage = <Redirect to='/home'></Redirect>
const page = (
<div>
<h2>請登入系統</h2>
<button onClick={this.props.login}>登入</button>
</div>
)
return this.props.userId > 0 ? redirectToPage : page
}
}
export default Login
我們首先將state.authReducer.userId取過來作為屬性,頁面內容有兩種可能性,如果userId<=0則顯示登入頁面,userId>0則顯示首頁(患者列表頁面)。其中的登入事件定義在src/Auth.redux.js中,如下所示:
// 用於登入、登出、註冊
// 定義事件型別
export const LOGIN = 'login'
export const LOGOUT = 'logout'
// 定義reducer
export function authReducer(state={userId: 0, userName: '遊客'}, action) {
switch (action.type) {
case LOGIN:
return { ...state, userId: 100, userName: '王一' }
case LOGOUT:
return { ...state, userId: 0, userName: '遊客' }
default:
return state
}
}
// 定義事件生成函式
export function login() {
let action = { type: LOGIN }
return action
}
export function logout() {
let action = { type: LOGOUT }
return action
}
接下來我們來看由App元件定義的導航頁面src/App.js,如下所示:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { Route, Link } from 'react-router-dom'
import { logout } from './Auth.redux'
import Home from './Home'
import PatientDetail from './PatientDetail'
import ArticleList from './ArticleList'
@connect(
(state) => {
return {
userId: state.authReducer.userId,
userName: state.authReducer.userName,
}
},
{ logout }
)
class App extends Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
<h2>使用者:{this.props.userName}</h2>
<button onClick={this.props.logout}>登出</button>
<ul>
<li><Link to='/home'>患者列表</Link></li>
<li><Link to='/home/patientDetail'>患者詳情</Link></li>
<li><Link to='/home/articleList'>文章列表</Link></li>
</ul>
<Route path='/home' exact component={Home}></Route>
<Route path='/home/patientDetail' component={PatientDetail}></Route>
<Route path='/home/articleList' component={ArticleList}></Route>
</div>
)
}
}
export default App
我們在頁面首部顯示使用者名稱,然後是登出按鈕,然後就是導航連結。我們在這裡假設Home元件代表的患者列表頁面,需要使用者登入後才能看,其他頁面則不需要。
我們接下來看患者列表頁面src/Home.js,如下所示:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { Route, Link, Redirect } from 'react-router-dom'
import { articleReducer, addArticle, removeArticle, addArticleAsync } from './Home.redux'
import HighBlood from './HighBlood'
import Diabete from './Diabete'
import PatientDetail from './PatientDetail'
import ArticleList from './ArticleList'
const diabetes = [
{'patientId': 201, 'patientName': 'D201'},
{'patientId': 202, 'patientName': 'D202'},
{'patientId': 203, 'patientName': 'D203'},
{'patientId': 204, 'patientName': 'D204'}
]
@connect(
(state) => {
return {
articleNum: state.articleReducer.articleNum,
userId: state.authReducer.userId
}
},
{ addArticle, removeArticle, addArticleAsync }
)
class Home extends Component {
constructor(props) {
super(props)
}
render() {
const title = '患者管理 v0.0.2'
const redirectToLogin = <Redirect to='/login'></Redirect>
const page = (
<div>
<h1>{title}</h1>
<span>文章數:{this.props.articleNum}</span><br />
<button onClick={this.props.addArticle}>新增文章</button><br />
<button onClick={this.props.removeArticle}>刪除文章</button>
<button onClick={this.props.addArticleAsync}>非同步新增</button>
<HighBlood></HighBlood>
<Diabete patients={diabetes}></Diabete>
</div>
)
return this.props.userId<=0 ? redirectToLogin : page
}
}
export default Home
這裡也將state.authReducer.userId取出來作為屬性,也分為兩種情況,一種是userId>0,此時顯示患者列表頁面,另一種是userId<=0,則跳轉到登入頁面。
Home元件所對應的Reducer為src/Home.redux.js,如下所示:
// 定義事件型別
export const ADD_ARTICLE = 'AddArticle'
export const REMOVE_ARTICLE = 'RemoveArticle'
// 定義reducer
export function articleReducer(state={}, action) {
if (!state.articleNum) {
state.articleNum = 0
}
switch (action.type) {
case ADD_ARTICLE:
return { ...state, articleNum: state.articleNum+1 }
case REMOVE_ARTICLE:
return { ...state, articleNum: state.articleNum-1 }
default:
return state
}
}
// 定義事件生成函式
export function addArticle() {
let action = { type: ADD_ARTICLE }
return action
}
export function removeArticle() {
let action = { type: REMOVE_ARTICLE }
return action
}
export function addArticleAsync() {
return dispatch => {
setTimeout( () => { dispatch(addArticle()) }, 2000)
}
}
登入功能前後端聯調
我們首先安裝Ajax支援庫:
npm install axios --save
因為我們的開發伺服器監聽在3000埠,我們伺服器的埠為8090,所以直接使用axios傳送Ajax請求會出現跨域問題,我們需要在package.json配置代理,將所有請求重定向到8090埠上去,如下所示:
......
"eslintConfig": {
"extends": "react-app"
},
"proxy": "http://localhost:8443"
}
我們來看登入相關功能,在src/Auth.redux.js檔案中,此時login事件就變成向伺服器端傳送請求,就變為非同步事件處理了,如下所示:
// 用於登入、登出、註冊
import axios from 'axios'
// 定義事件型別
export const LOGIN = 'login'
export const LOGOUT = 'logout'
export const ON_LOGIN = 'onLoginRst'
const initState = {
userId: 0,
userName: '遊客',
roleId: 1,
roleName: '醫生'
}
// 定義reducer
export function authReducer(state=initState, action) {
switch (action.type) {
case LOGIN:
return { ...state, userId: 100, userName: '王一' }
case LOGOUT:
return { ...state, userId: 0, userName: '遊客' }
case ON_LOGIN:
let data = action.data
return { ...state, userId: data.userId, userName: data.userName}
default:
return state
}
}
// 定義事件生成函式
export function login() {
return dispatch => {
axios.get('/loginReactLearnUserAjax?loginName=1350&loginPwd=123').then(
res => {
if (200 == res.status) {
dispatch(onLoginRst(res.data))
}
}
)
}
}
export function onLoginRst(data) {
return { type: ON_LOGIN, data: data}
}
export function logout() {
let action = { type: LOGOUT }
return action
}
我們伺服器端使用node.js,處理這個請求首先在wkys/index.js中新增路由:
......
// React測試
var reactHdlr = require('./controller/c_react.js');
......
// React學習測試
handlers['/loginReactLearnUserAjax'] = reactHdlr.loginReactLearnUserAjax;
具體的請求處理函式在controller/c_react.js檔案中,如下所示:
/**
*
*/
var url = require("url");
var qs = require("querystring");
var fs = require("fs");
var exec = require("child_process").exec;
var appGlobal = require("../app_global.js");
var baseController = require('../controller/c_base_controller.js');
var db = require("../model/m_mysql.js");
function loginReactLearnUserAjax(request, response) {
var params = baseController.getRequestParams(request);
var postParams = request.dataObj;
var loginName = params.loginName;
var loginPwd = params.loginPwd;
var obj = new Object();
obj.status = 'Ok';
obj.userId = 201;
obj.userName = '東方不敗';
obj.roleId = 108;
obj.roleName = '超級管理員';
baseController.sendResponseJson(response, obj);
}
// 對外公共介面定義
exports.loginReactLearnUserAjax = loginReactLearnUserAjax;
小結
至此一個小型應用就基本完成了,由此可以看出,寫一個完整的程式,這方面的工作量還是比較大的,尤其是我們這個小應用中,還沒有考慮頁面的佈局設計,所以做一個React+Router的應用還是有很高的門檻的。幸好有牛人們給我們寫了一些開源框架,使我們可以拿來即用,在下一節中我們將以一個開源React後臺管理框架為基礎,開發我們的後臺管理系統。
相關文章
- React開發管理後臺實踐1React
- React開發管理後臺實踐3---新增新頁面React
- Django框架急速開發內容管理系統後臺Django框架
- React開發管理後臺0React
- Django Admin後臺管理:高效開發與實踐Django
- JAVA後臺開發學習(5)Java
- React 後臺管理模板React
- 最佳實踐丨雲開發CloudBase內容稽核能力Cloud
- Java後臺開發學習(3)——MongoDBJavaMongoDB
- react搭建後臺管理(react初窺)React
- 一小時完成後臺開發:DjangoRestFramework開發實踐DjangoRESTFramework
- Java後臺開發學習(1)——User介面Java
- 後臺開發 -- 核心技術與應用實踐
- 待學習內容
- 已學習內容
- CSS學習內容CSS
- Java後臺開發學習(4)——Spring Data JpaJavaSpring
- Java後臺開發學習(2)——攔截器Java
- 如何在網站後臺修改,輕鬆管理網站內容網站
- web前端開發入門,學習路徑以及具體的學習內容Web前端
- PBootCMS後臺系統內容修改boot
- Angular開發實踐(八): 使用ng-content進行元件內容投射Angular元件
- WePY – 小程式敏捷開發實踐(演講內容整理)丨掘金開發者大會敏捷
- WePY - 小程式敏捷開發實踐(演講內容整理)丨掘金開發者大會敏捷
- 資料治理:資料標準管理的內容和實踐!
- 資料治理:資料標準管理的內容和實踐
- 學習內容介紹
- 事件驅動架構在 vivo 內容平臺的實踐事件架構
- 愛奇藝內容中臺之Serverless應用與實踐Server
- 淺談因果推斷與在內容平臺的實踐
- 用後臺開發的邏輯理念學習VUEVue
- 後臺開發:核心技術與應用實踐 -- C++C++
- 部落格內容管理實現
- 案例丨「PB級資料」股份制銀行內容管理平臺的探索與實踐
- 大魚號內容分發工具,多個平臺分發內容,一鍵管理200+賬號
- 後臺開發-核心技術與應用實踐--TCP協議TCP協議
- 前端完全基於Layui的LarryMS後臺管理模板,後臺完全基於ThinkPHP5.x的LarryCMS內容管理系統前端UIPHP
- 【PWA學習與實踐】(8)使用Service Worker進行後臺同步 – Background Sync