一、react 開發(fā)環(huán)境
- create-react-app 官方腳手架,生成文件格式,安裝:
cnpm i -g create-react-app
- 創(chuàng)建一個應(yīng)用:
create-react-app yjw
- 進(jìn)入到 yjw 目錄下:
- 可以看到自動生成的幾個文件:
README.md、package.json、src、node_modules、public
- 執(zhí)行命令:
npm start; - 在瀏覽器輸入:
localhost:3000
腳手架相關(guān)命令:
如何使用 create-react-app :
①npm install --save redux : 安裝第三方庫 redux;
②npm run eject : 生成配置文件,可以自定義配置 webpack;
③擴(kuò)展 package.json 里的 script 字段,擴(kuò)展 npm run 命令。
二、ES6 簡單介紹
- ES6 的詳細(xì)學(xué)習(xí)請參照 ES6 的快速入門與使用。
- ES6 是新的 JavaScript 語法標(biāo)準(zhǔn);
- 使用 babel 語法轉(zhuǎn)換器,使其支持低版本瀏覽器;
- 流行的庫基本都是基于 ES6 構(gòu)建,React 默認(rèn)使用 ES6 新語法開發(fā)。
1、塊級作用域、字符串、函數(shù)
1.1、塊級作用域
- 定義變量使用 let 替代 var;
- const 定義不可修改的變量;
- 作用域:{}。
1.2、字符串
- 模板字符串: 兩個反引號,在兩個反引號之間獲取變量:
${變量名};
1.3、函數(shù)
- 可以設(shè)置參數(shù)默認(rèn)值;
- 箭頭函數(shù):
- 參數(shù)只有一個時,參數(shù)外面的小括號可以省略;
- 只有一條 return 語句時,可以省略 return 和大括號;
- 可以保持 this 作用域。
- 展開運(yùn)算符。
2、對象擴(kuò)展、解構(gòu)
2.1、對象的擴(kuò)展:
- Object.keys、values、entries:
- keys:獲取到對象 key 組成的數(shù)組;
- values:獲取到對象 value 組成的數(shù)組;
- entries:獲取到兩個數(shù)組,分別有對象的 key 和 value 組成;
- 說明:定義一個對象時,鍵可加引號可不加引號,默認(rèn)會被認(rèn)為是一個字符串,如果想要用外面定義的變量作為 key,可按如下方式使用(計算屬性):
const name = 'yijiang';
const person = {
[name] : 18
};
- 對象方法簡寫,計算屬性:
const obj = {
hello:function(){//之前寫法},
hello1(){//現(xiàn)在寫法}
}
- 展開運(yùn)算符(不是 ES6 標(biāo)準(zhǔn),但是 babel 也支持)
//合并兩個對象
const obj1 = {name:'yijiang',age:18};
const obj2 = {score:100,height:180};
const obj3 = {...obj1,...obj2};
2.2、解構(gòu)賦值
- 函數(shù)也可以多返回值了:
- 數(shù)組解構(gòu);
- 對象解構(gòu)。
- 數(shù)組解構(gòu):
const arr = ['yijiang',18];
const [name,age] = arr;
- 對象解構(gòu):
const obj = {name:'yijiang',course:'computer'};
const {name,course} = obj;
3、類、模塊化等
3.1 類
- 提供 class 的語法糖:
- 是 prototype 的語法糖;
- extends 繼承;
- constructor 構(gòu)造函數(shù)。
- ES6 中新出現(xiàn)的數(shù)據(jù)結(jié)構(gòu):
- Set,元素不可重復(fù);
- Map;
- Symbol。
3.2 模塊化
- ES6 中自帶了模塊化機(jī)制,告別 seajs 和 require.js
- export , export default;
- import {},import;
export 的內(nèi)容,在 import 時,需要使用 {} 來導(dǎo)入變量名/類名;
export default 的內(nèi)容,在 import 時直接導(dǎo)入變量名/類名即可。
- node 現(xiàn)在還不支持,還需要用 require 來加載文件。
3.3 其它:還有一些特性,雖然不在 ES6 的范圍,但是也被 babel 支持,普遍被大家接受和使用(需要安裝插件)
- 對象擴(kuò)展符(Babel-plugin-transform-object-rest-spread 插件,支持?jǐn)U展符號),函數(shù)綁定;
- 裝飾器;
- async await。
3.4 其它的特性
- promise;
- 迭代器和生成器;
- 代理 proxy。
三、express + mongodb 基礎(chǔ)
- express + mongodb 開發(fā) web 后臺接口;
- express 開發(fā) web 接口;
- 非關(guān)系型數(shù)據(jù)庫 mongodb(存儲類似 json 的數(shù)據(jù));
- 使用 nodejs 的 mongoose 模塊鏈接和操作 mongodb。
1. express
- 基于 nodejs,快速、開發(fā)、極簡的 web 開發(fā)框架;
- 安裝:
npm install --save express。 - 創(chuàng)建服務(wù)器:
//新建一個文件 server.js
const express = require('express');
const app = express();
app.get('/',function(req,res){
res.send('<h2>Hello World</h2>');
});
//返回 json 數(shù)據(jù)
app.get('/data',function(req,res){
res.json({name: 'yjw',age: 18});
})
app.listen(3002, ()=>{
console.log('監(jiān)聽到了端口 3002');
})
//在終端進(jìn)入到 server.js 所在的文件夾,然后執(zhí)行 node server.js 即可啟動服務(wù)
//如果對文件中的內(nèi)容進(jìn)行修改,必須要先重新啟動才能生效(ctrl + c,node server.js)
//如果想要修改 server.js 中的文件,不進(jìn)行重啟就使修改的內(nèi)容生效,可使用插件 nodemon。首先全局安裝 nodemon 插件;然后使用 nodemon server.js 進(jìn)行啟動;以后刷新瀏覽器頁面即可。
- 其它的特性:
- app.get、app.post 分別開發(fā) get 和 post 接口;
- app.use 使用模塊;
- res.send(文本)、res.json(json)、res.sendfile(文件) 響應(yīng)不同的內(nèi)容。
2. mongodb + mongoose
- 非關(guān)系型數(shù)據(jù)庫
- 官網(wǎng) https://www.mongodb.com/ 下載安裝 mongodb;
- 安裝 mongoose:
npm install mongoose --save; - 通過 mongoose 操作 mongodb,存儲的就是 json,相對 mysql 來說,要易用很多。
2.1. mongoose 的基礎(chǔ)使用
- connect 鏈接數(shù)據(jù)庫;
- 定義文檔模型,schema 和 model 新建模型;
- String、Number 等數(shù)據(jù)結(jié)構(gòu);
- create、remove、update 分別用來增、刪、改的操作;
- find 和 findOne 用來查詢數(shù)據(jù)。
//找到 mongodb 安裝目錄,然后在控制臺執(zhí)行 mongo,即可連接上 MongoDB
const express = require('express');
const mongoose = require('mongoose');
// 鏈接 mongoose
const DB_URL = 'mongodb://127.0.0.1:27017';
mongoose.connect(DB_URL);
// 此句測試 是否鏈接成功,可以刪除
mongoose.connection.on('connected',function(){
console.log('mongoose 鏈接成功啦~')
})
// 類似于 mysql 的表,mongo 里面有文檔、字段的概念
const User = mongoose.model('user',new mongoose.Schema({
name:{type:String,require:true},
age:{type:Number,require:true}
}))
//增加數(shù)據(jù)
// User.create({
// name:'mike',
// age:18
// },function(err,data){
// if(!err){
// console.log('增加數(shù)據(jù)成功:',data)
// }else{
// console.log('增加數(shù)據(jù)失敗:',err)
// }
// })
// 刪除數(shù)據(jù)
// User.remove({name:'yijiang'},function(err,data){
// console.log('刪除數(shù)據(jù)成功:',data)
// })
// 更新數(shù)據(jù),$set 可以省略
User.update({name:'mike'},{'$set':{age:28}},function(err,data){
console.log('更新數(shù)據(jù)成功:',data)
})
// 新建app
const app = express();
app.get('/',function(req,res){
res.send('<h2>Hello New App</h2>')
})
app.get('/data',function(req,res){
// 查詢數(shù)據(jù)
User.find({name:'mike'},function(err,data){ //還有 findOne 方法,該方法返回一個 json
res.json(data)
})
})
app.listen(9003,function(){
console.log('新建 APP')
})
2.2. express + mongodb 實(shí)戰(zhàn)(后面講解)
- mongod --config /usr/local/etc/mongod.conf 后臺啟動;
- express 結(jié)合 mongodb;
- 封裝 mongoose。
2.3. 后續(xù)進(jìn)階
- express 和 mongodb 結(jié)合:
- mongodb 獨(dú)立工具函數(shù);
- express 使用 body-parser 支持 post 參數(shù);
- 使用 cookie-parser 存儲登錄信息 cookie。
四、React 基礎(chǔ)簡述
- 這里只是簡單回顧一下
props、state、生命周期函數(shù)的相關(guān)知識,詳細(xì)學(xué)習(xí)請參考:React 之高級使用 - 需要綁定 this 的三種解決方案:
- ①在 constructor 方法中對方法進(jìn)行綁定:
this.aaa = this.aaa.bind(this); - ②調(diào)用函數(shù)時,使用箭頭函數(shù)進(jìn)行調(diào)用
() => this.aaa(); - ③定義函數(shù)時,使用箭頭函數(shù)。
- ①在 constructor 方法中對方法進(jìn)行綁定:
- 安裝 babel-plugin-import,進(jìn)行按需加載:
- 在 package.json 中的 plugins 按需加載:
"babel": {
"presets": [
"react-app"
],
"plugins": [
["import",{"libraryName": "antd-mobile","style": "css"}]
]
}
- 對 props、state 傳值的簡單使用:
import React,{Component} from 'react'
import {Button, List} from 'antd-mobile'
// import 'antd-mobile/dist/antd-mobile.css'
class App extends Component{
render(){
const director = '李云龍';
return (
<div>
<h2>獨(dú)立營營長:{director}</h2>
<Yiying boss='yijiang'/>
<Erying name='jiang' />
</div>
)
}
}
// 如果組件只有 render 函數(shù),還可以用函數(shù)的形式寫組件
function Erying(props){
return <h2>二營營長:{props.name}</h2>
}
class Yiying extends Component{
constructor(props){
super(props);
this.state = {soldiers:['虎子','狗子','嘎子']}
}
show(e){
alert(e.target.innerText)
}
clickAntButton(e){
alert(e.target.innerText)
}
render(){
return (
<div>
<h2>一營營長:{this.props.boss}</h2>
<Button type='primary' onClick={this.clickAntButton}>這里是ant Button </Button>
<List renderHeader='士兵列表' renderFooter='收兵'>
{this.state.soldiers.map((v,idx) => {
return (
<List.Item
extra='快來參軍吧'
key={idx}
onClick={this.show}
arrow='up'
>士兵:{v}</List.Item>)
})}
</List>
</div>
)
}
}
export default App
-
生命周期函數(shù)執(zhí)行順序圖:
生命周期圖.png
五、redux 的使用
1.redux基本概念
-
是一個專注于狀態(tài)管理的庫:
- redux 專注于狀態(tài)管理,和 react 解耦,也可以和 vue、angular 結(jié)合使用;
- 單一狀態(tài),單向數(shù)據(jù)流;
- 核心概念:store、state、action、reducer。
-
redux 的結(jié)構(gòu)可以模仿如下結(jié)構(gòu):
redux 結(jié)構(gòu).png -
redux 的使用方法:
redux 的使用方法 結(jié)合上圖理解以下代碼:
// src/index.js
import {createStore} from 'redux'
// 新建 store
// 通過 reducer 建立,reducer 根據(jù)老的狀態(tài)和 action 生成新的 state
function counter(state=0,action){
switch(action.type){
case '加機(jī)關(guān)槍':
return state + 1;
case '減機(jī)關(guān)槍':
return state -1;
default:
return 10;
}
}
//通過 reducer 新建 store
const store = createStore(counter);
const init = store.getState();
console.log('初始化 state:',init); //初始化 state: 10
function listener(){
const count = store.getState();
console.log(`現(xiàn)有機(jī)槍 ${count} 把。`)
}
// 監(jiān)聽,每次 state 修改都會調(diào)用 listener
store.subscribe(listener)
// 現(xiàn)有機(jī)槍 11 把。
// 現(xiàn)有機(jī)槍 12 把。
// 現(xiàn)有機(jī)槍 11 把。
store.dispatch({type:'加機(jī)關(guān)槍'})
store.dispatch({type:'加機(jī)關(guān)槍'})
store.dispatch({type:'減機(jī)關(guān)槍'})
- 以上代碼中的 subscribe 方法可以進(jìn)一步優(yōu)化:
store.subscribe(()=>{
console.log(`現(xiàn)有機(jī)槍 ${store.getState()} 把`)
})
2.redux 如何和 react 一起使用
2.1. 手動連接 react 和 redux

圖片.png
- 個人理解:dispatch(action)時,會自動將 action 傳給 reducer,然后 reducer 進(jìn)行相應(yīng)處理;如果處理中 state 發(fā)生變化,會觸發(fā) store.subscribe(func)。
- src 文件夾下有三個文件,內(nèi)容分別如下:
// index.js
import React from 'react'
import {render} from 'react-dom'
import {createStore} from 'redux'
import App from './App'
import {reducer, addGun, removeGun} from './index.redux'
const store = createStore(reducer)
function show(){
render(
<App store={store} addGun={addGun} removeGun={removeGun}/>,
document.getElementById('root')
)
}
show()
store.subscribe(show)
// App.js
import React from 'react'
import {Button} from 'antd-mobile'
class App extends React.Component{
render(){
const {store, addGun, removeGun} = this.props
return (
<div>
<h2>現(xiàn)有槍支:{store.getState()}</h2>
<Button type='primary' inline onClick={()=>{store.dispatch(addGun())}}>增加槍支</Button>
<Button type='primary' inline onClick={()=>store.dispatch(removeGun())}>減少槍支</Button>
</div>
)
}
}
export default App
// index.redux.js
const INCREASE_TYPE = 'INCREASE'
const REDUCE_TYPE = 'REDUCE'
export function addGun(){
return {type:INCREASE_TYPE}
}
export function removeGun(){
return {type:REDUCE_TYPE}
}
export function reducer(state=0,action){
switch (action.type){
case 'INCREASE':
return state + 1
case 'REDUCE':
return state -1
default:
return 10
}
}
2.2. 處理異步、調(diào)試工具、更優(yōu)雅的將 react 和 redux 結(jié)合:
- redux 異步處理,需要使用 redux-thunk 插件
- 調(diào)試工具:npm install redux-devtools-extension 并且開啟
- 使用 react-redux 優(yōu)雅的連接 react 和 redux
2.2.1. redux異步處理:
redux 默認(rèn)處理同步,異步任務(wù)需要 redux-thunk 中間件:
- npm i --save redux-thunk
- 使用 applyMiddleware 開啟 thunk 中間件(見下面代碼)
- action 可以返回函數(shù),使用 dispatch 提交 action
2.2.2. 調(diào)試工具
- 親測發(fā)現(xiàn),只要在 Chrome 瀏覽器中安裝插件
Redux DevTools; - 然后再從 redux 中引入 compose
- 將原來創(chuàng)建 store 的方式修改一下:
//原來創(chuàng)建 store 的方式
const store = createStore(reducer,applyMiddleware(thunk))
// compose 將函數(shù)組合到一起 , 在 Chrome 中安裝插件 redux 后,將上面創(chuàng)建 store 方式改為如下形式,在瀏覽器中調(diào)試清晰方便
// 現(xiàn)在創(chuàng)建 store 的方式
const store = createStore(reducer,compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : ()=>{}
))
- 現(xiàn)在 src 文件夾下的代碼如下:
// index.js
import React from 'react'
import {render} from 'react-dom'
import {createStore, applyMiddleware, compose} from 'redux'
import thunk from 'redux-thunk'
import App from './App'
import {reducer, addGun, removeGun, addGunAsync} from './index.redux'
// const store = createStore(reducer,applyMiddleware(thunk))
// compose 將函數(shù)組合到一起 , 在 Chrome 中安裝插件 redux 后,將上面創(chuàng)建 store 方式改為如下形式,在瀏覽器中調(diào)試清晰方便
const store = createStore(reducer,compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : ()=>{}
))
function show(){
render(
<App store={store} addGun={addGun} removeGun={removeGun} addGunAsync={addGunAsync}/>,
document.getElementById('root')
)
}
show()
store.subscribe(show)
// App.js
import React from 'react'
import {Button} from 'antd-mobile'
class App extends React.Component{
render(){
const {store, addGun, removeGun, addGunAsync} = this.props
return (
<div>
<h2>現(xiàn)有槍支:{store.getState()}</h2>
<Button type='primary' inline onClick={()=>{store.dispatch(addGun())}}>增加槍支</Button>
<Button type='primary' inline onClick={()=>{store.dispatch(addGunAsync())}}>遲緩加槍</Button>
<Button type='primary' inline onClick={()=>store.dispatch(removeGun())}>減少槍支</Button>
</div>
)
}
}
export default App
// index.redux.js
const INCREASE_TYPE = 'INCREASE'
const REDUCE_TYPE = 'REDUCE'
// action creator
export function addGun(){
return {type:INCREASE_TYPE}
}
export function removeGun(){
return {type:REDUCE_TYPE}
}
//異步
export function addGunAsync(){
// thunk 插件的作用,這里可以返回函數(shù)
return dispatch => {
setTimeout(()=>{
dispatch(addGun())
},2000)
}
}
export function reducer(state=0,action){
switch (action.type){
case 'INCREASE':
return state + 1
case 'REDUCE':
return state -1
default:
return 10
}
}
2.2.3. 使用 react-redux
- 首先安裝插件: npm install --save react-redux
- 忘記 subscribe,記住 reducer,action 和dispatch 即可
- react-redux 提供 Provider 和 connect 兩個接口來連接
- 具體使用:
- Provider 組件在應(yīng)用最外層,傳入 store 即可,只用一次
- connect 負(fù)責(zé)在組件內(nèi)從外部獲取組件需要的參數(shù),這時組件內(nèi)不需要顯式觸發(fā)事件(dispatch),直接傳 actionCreator 即可
- connect 可以用裝飾器的方式來寫
- src 文件夾下內(nèi)容:
// index.js
import React from 'react'
import {render} from 'react-dom'
import {createStore, applyMiddleware, compose} from 'redux'
import thunk from 'redux-thunk'
import {Provider} from 'react-redux'
import App from './App'
import {reducer} from './index.redux'
const store = createStore(reducer,compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : ()=>{}
))
render(
(
<Provider store={store}>
<App />
</Provider>
),
document.getElementById('root')
)
// App.js
import React from 'react'
import {Button} from 'antd-mobile'
import {connect} from 'react-redux'
import {addGun, removeGun, addGunAsync} from './index.redux'
class App extends React.Component{
render(){
const {num, addGun, removeGun, addGunAsync} = this.props;
return (
<div>
<h2>現(xiàn)有槍支:{num} 支</h2>
<Button type='primary' inline onClick={addGun}>增加槍支</Button>
<Button type='primary' inline onClick={addGunAsync}>遲緩加槍</Button>
<Button type='primary' inline onClick={removeGun}>減少槍支</Button>
</div>
)
}
}
const mapStateToProps = state => {
return {num:state}
}
const actionCreators = {addGun, removeGun, addGunAsync}
App = connect(mapStateToProps,actionCreators)(App)
export default App
// index.redux.js
const INCREASE_TYPE = 'INCREASE'
const REDUCE_TYPE = 'REDUCE'
// action creator
export function addGun(){
return {type:INCREASE_TYPE}
}
export function removeGun(){
return {type:REDUCE_TYPE}
}
//異步
export function addGunAsync(){
// thunk 插件的作用,這里可以返回函數(shù)
return dispatch => {
setTimeout(()=>{
dispatch(addGun())
},2000)
}
}
export function reducer(state=0,action){
switch (action.type){
case 'INCREASE':
return state + 1
case 'REDUCE':
return state -1
default:
return 10
}
}
- 使用 裝飾器優(yōu)化 connect 代碼:
- 彈出個性化配置:npm run eject
- 安裝插件:npm i babel-plugin-transform-decorators-legacy
- package.json 里 babel 加上 plugins 配置:
"babel": {
"presets": [
"react-app"
],
"plugins": [
[
"import",
{
"libraryName": "antd-mobile",
"style": "css"
}
],
"transform-decorators-legacy"
]
},
- 使用裝飾器,主要是對 connect 進(jìn)行優(yōu)化:
// App.js
import React from 'react'
import {Button} from 'antd-mobile'
import {connect} from 'react-redux'
import {addGun, removeGun, addGunAsync} from './index.redux'
// const mapStateToProps = state => {
// return {num:state}
// }
// const actionCreators = {addGun, removeGun, addGunAsync}
// App = connect(mapStateToProps,actionCreators)(App)
@connect(
state => ({num:state}),
{addGun, removeGun, addGunAsync}
)
class App extends React.Component{
render(){
const {num, addGun, removeGun, addGunAsync} = this.props;
return (
<div>
<h2>現(xiàn)有槍支:{num} 支</h2>
<Button type='primary' inline onClick={addGun}>增加槍支</Button>
<Button type='primary' inline onClick={addGunAsync}>遲緩加槍</Button>
<Button type='primary' inline onClick={removeGun}>減少槍支</Button>
</div>
)
}
}
export default App
六、react-router4
- React 官方推薦的路由庫,4 是最新版本
- 4 是全新的版本,和之前版本不兼容,瀏覽器和 RN 均兼容;
- React 開發(fā)單頁應(yīng)用必備,踐行路由即組件的概念;
- 核心概念:動態(tài)路由、Route、Link、Switch。
1、初識 router4
- 安裝: npm i --save react-router-dom
- router4 使用 react-router-dom 作為瀏覽器端的路由
- 忘掉 router2 的內(nèi)容
1.1、入門組件
- BrowserRouter,包裹整個應(yīng)用;
- Route 路由對應(yīng)渲染的組件,可以嵌套,語法:
<Route path='/path' component={要渲染的組件}></Route>; - Link 跳轉(zhuǎn)專用,語法:
<Link to='/path'>展示的名稱</Link>。 - 示例:這里只在 index.js 文件中進(jìn)行添加
// index.js
import React from 'react'
import {render} from 'react-dom'
import {createStore, applyMiddleware, compose} from 'redux'
import thunk from 'redux-thunk'
import {Provider} from 'react-redux'
import {BrowserRouter, Route, Link} from 'react-router-dom'
import App from './App'
import {reducer} from './index.redux'
const store = createStore(reducer,compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : ()=>{}
))
function Erying(){
return <h2>歡迎來到二營</h2>
}
class Qibinglian extends React.Component{
render(){
return <h2>這里是騎兵連</h2>
}
}
render(
<Provider store={store}>
<BrowserRouter>
<div>
<ul>
<li><Link to='/'>一營</Link></li>
<li><Link to='/erying'>二營</Link></li>
<li><Link to='/qibinglian'>騎兵連</Link></li>
</ul>
<Route path='/' exact component={App}></Route>
<Route path='/erying' component={Erying}></Route>
<Route path='/qibinglian' component={Qibinglian}></Route>
</div>
</BrowserRouter>
</Provider>
,
document.getElementById('root')
)
1.2、其它組件
- url 參數(shù):Route 組件參數(shù)可用冒號標(biāo)識參數(shù);
class Test extends React.Component{
render(){
console.log(this.props.match.params.location)
return <h2>測試組件</h2>
}
}
===============================
<ul>
<li><Link to='/'>首頁</Link></li>
<li><Link to='/erying'>二營</Link></li>
<li><Link to='/qibinglian'>騎兵連</Link></li>
</ul>
<Route path='/' exact component={App}></Route>
<Route path='/:location' exact component={Test}></Route>
點(diǎn)擊“二營”、“騎兵連”會顯示 Test 組件,并且可以打印相關(guān)的信息,這里會顯示:“erying”、“qibinglian”。
- Redirect 組件:跳轉(zhuǎn);
- Switch 只渲染一個子 Route 組件。
// index.js
import React from 'react'
import {render} from 'react-dom'
import {createStore, applyMiddleware, compose} from 'redux'
import thunk from 'redux-thunk'
import {Provider} from 'react-redux'
import {BrowserRouter, Route, Link, Redirect,Switch} from 'react-router-dom'
import App from './App'
import {reducer} from './index.redux'
const store = createStore(reducer,compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : ()=>{}
))
class Erying extends React.Component{
render(){
return <h2>二營</h2>
}
}
function Qibinglian(){
return <h2>騎兵連</h2>
}
class Test extends React.Component{
render(){
console.log(this.props.match.params.location)
return <h2>這里應(yīng)該是 404 頁面喲~ <br/>沒有{this.props.match.params.location}這個路徑喔~</h2>
}
}
render(
<Provider store={store}>
<BrowserRouter>
<div>
<ul>
<li><Link to='/'>首頁</Link></li>
<li><Link to='/erying'>二營</Link></li>
<li><Link to='/qibinglian'>騎兵連</Link></li>
</ul>
{/* <Redirect to='/qibinglian' component={Qibinglian}></Redirect> */}
<Switch>
{/* Switch 里面只渲染命中的第一個 Route */}
<Route path='/' exact component={App}></Route>
<Route path='/erying' component={Erying}></Route>
<Route path='/qibinglian' component={Qibinglian}></Route>
<Route path='/:location' component={Test}></Route>
</Switch>
</div>
</BrowserRouter>
</Provider>
,
document.getElementById('root')
)
- 復(fù)雜的 redux 應(yīng)用,會遇到多個 reducer 的情況,用 combineReducers 進(jìn)行合并。
七、項目開發(fā)
- 這里不再貼詳細(xì)代碼,只列出用到的對應(yīng)的知識點(diǎn)。詳細(xì)代碼可參照項目地址:項目地址
1、前后端聯(lián)調(diào)
- 使用 axios 發(fā)送異步請求:
- 如何發(fā)送,端口不一致時,使用 proxy 配置轉(zhuǎn)發(fā);
- axios 攔截器,統(tǒng)一 loading 處理;
- redux 里使用異步數(shù)據(jù),渲染頁面;
- 攔截器:interceptor。
2、登錄注冊功能的實(shí)現(xiàn)
2.1、 頁面文件結(jié)構(gòu);
- 骨架結(jié)構(gòu)實(shí)現(xiàn):
- 組件放在 Component 文件夾下面;
- 頁面放在 Container 文件夾下面;
- 頁面入口處獲取用戶信息,決定跳轉(zhuǎn)到哪個頁面。
2.2、web 開發(fā)模式;
- 基于 cookie 用戶驗(yàn)證:
- express 依賴 cookie-parser,需要安裝:
npm i cookie-parser --save; - cookie 類似于一張身份卡,登陸后服務(wù)器端返回,你帶著 cookie 就可以訪問受限資源;
- cookie 的管理:瀏覽器會自動處理。
- express 依賴 cookie-parser,需要安裝:
-
開發(fā)流程:
開發(fā)流程



