項目代碼 "從零開始簡書項目" 從我第一次接觸 這個框架已經過了快一年的時間,陪伴我從前端小白到前端工程師,前端時間也是使用了 +`vue vue`這一塊,也算是比較熟練了,對底層也有一些瞭解,我開始了react的產生了一些興趣 第一次看 慕課網上的一個免費課程 "React 16實現訂單列 ...
項目代碼 從零開始簡書項目
從我第一次接觸vue
這個框架已經過了快一年的時間,陪伴我從前端小白到前端工程師,前端時間也是使用了 ts
+vue
這樣的組合寫代碼,明顯感覺vue與ts似乎沒有產生比較好的化學反應,而vue
這一塊,也算是比較熟練了,對底層也有一些瞭解,我開始了react的產生了一些興趣
第一次看react
慕課網上的一個免費課程React 16實現訂單列表及評價功能,還不錯,讓我大致瞭解了react
也就是jsx
的一些代碼風格
因為可能寫vue
的時間比較久了,轉到react
還沒有我想象的的難度那麼大,一切似乎都順風順水,後面我就開始看慕課網的React 16.4 開發簡書項目 從零基礎入門到實戰,老師將前面基礎講的比較全面,雖然沒有過api,但是講了 react的周邊 redux
, redux-thunk
, redux-saga
react-redux
,等等,老師是很有水平
但是正在寫課程代碼裡面 用了大量的這樣的庫,我在學的過程裡面,感覺不太理解這些庫的內部實現,這一點感覺到react上面的一些吃力的地方,還有待學習吧,目前只能是入門了react,感覺現在的前端開發,不是會js
,就能寫出代碼的了,要學習各種各樣的各種庫的API,只會用,不瞭解其原理,今年是這個庫,明年是哪個庫,已經不是前端開發者
了 是前端框架使用者
學習成本過高,陷入到一種比較迷茫的階段,有點不知所措,
本次總結的重點,總結老師的項目架構,數據與數據與視圖的完全解耦,是一個非常完美的開發方式,同時具備靈活性,但是非常萬金油,項目這樣搭建,非常易於維護
看一些最後的效果圖
使用到的技術棧
react react-dom react
項目開發必備
redux react
的數據管理工具
redux-thunk redux
的中間件,讓redux
的dispatch
支持非同步操作
immutable 保證數據的不可變性,配合PureComponent
使用,效果拔群
styled-components 使用js的方式寫css
,是比less
,更加好用的工具
react-transition-group react裡面比較好用的動畫庫
axios 支持Promise
的ajax
庫
mockjs 數據模擬庫 使用他將不在需要在接觸第三方去生成介面
react-loadable 讓react
可以非同步載入組件的插件
react-router-dom react
的路由處理庫react-router和react-router-dom的區別
使用的技術比較多,是很完成的項目開發方式
頁面與redux的交互
pages
- index
- store
- index.js store的出口
- reducer.js 組件中數據的創建於修改
- actiontypes.js 定製統一的type值,用於修改reducer裡面的值
- actionCreators.js 生成action,觸發reducer,去進行數據修改
- index.js 視圖
- style.js styled css
每個頁面結構都是這樣的,在最外面的reducer
裡面進行每個頁面中的reducer
的合併,這樣做達到了
頁面中的視圖
與數據
的完全解耦
頁面
與頁面
之前的數據完全解耦
項目結構變得非常清楚,非常利於維護
修改一個數據的流程
- 在組件的視圖中, 通過
react-redux
裡面的connent
獲取state
dispatch
,庫幫我們將state
dispatch
掛載到了this.props
中,
const mapState = state => ({
title: state.detail.get('title'), // immutable數據 獲取state樹中的detail分支下的title
content: state.detail.get('content')
})
const mapDispatch = dispatch => ({
getDetail(id) { // 視圖中觸發該方法 方法內部觸發dispatch 獲取由actionCreators生成的action,交給reducer
//.. 發送dispatch 操作reducer
}
})
export default connect(
mapState,
mapDispatch
)(withRouter(Detail))
- 導入當前文件夾下的
store/actionCreaters.js
,在mapDispatch裡面發送action給reducer
const mapDispatch = dispatch => ({
getDetail(id) {
// 視圖中觸發該方法 方法內部觸發dispatch 獲取由actionCreators生成的action,交給reducer
reducer dispatch(actionCreators.getDetail(id))
}
})
- 在
actionCreators.js
中已經非同步操作,或者直接發放action
import { actionType } from './index' // 所有數據來源於index中
import axios from 'axios'
import { fromJS } from 'immutable'
function _getDetail(data) { // 私有方法
return {
type: actionType.GET_TEXT_DETAIL, //action後返回出去 視圖中的dispatch action
data: fromJS(data)
}
}
//
function getDetail (id) {
return dispatch => {
//攜帶動態參數
// axios.get(`/textdetail?id=${id}`)
axios.get(`/textdetail`)
.then(res => {
console.log(res.data);
dispatch(_getDetail(res.data))
})
.catch(res => {
console.log(res);
})
}
}
export default {
getDetail // 暴露出去改視圖調用
}
這裡就一定看看store/index.js
是這麼協調數據的
import actionCreators from './actionCreators'
import actionType from './actionType'
import reducer from './reducer'
export { reducer, actionType, actionCreators }
很簡單,就是將單個store
的入口統一了
上面的actionCreators.js
導入了actionType
所以我們看看store/actionType
寫了什麼數據
export default {
GET_TEXT_DETAIL: "get_text_detail"
}
對,就是action的type的倉庫,現在dispatch已經得到了action,reducer裡面的就會接收到dispatch發送的action
import { actionType } from './index'
import { fromJS } from 'immutable'
const defaultState = fromJS({
title: '',
content: ``,
})
export default (state = defaultState, action) => {
switch (action.type) {
case actionType.GET_TEXT_DETAIL:
console.log(action.data);
return state.merge({
title: action.data.get('title'),
content: action.data.get('content')
})
default:
return state
}
}
這裡就是匹配type,我們的type都從一個地方獲取的,保證了代碼出現失誤的幾率,通過 state.merge() 改變多條數據,頁面發生變化,這就完成了數據的變化
雖然過程很複雜,但是明顯感覺到,代碼耦合性非常低,決定了這樣會的項目結構可以完成比較大型的項目,
這裡說的可能不是很清楚 可以看github
上面的項目代碼從零開始簡書項目