摘要:更多相關介紹請看這特點僅僅只是虛擬最大限度減少與的交互類似于使用操作單向數據流很大程度減少了重復代碼的使用組件化可組合一個組件易于和其它組件一起使用,或者嵌套在另一個組件內部。在使用后,就變得很容易維護,而且數據流非常清晰,容易解決遇到的。
歡迎移步我的博客閱讀:《React 入門實踐》
在寫這篇文章之前,我已經接觸 React 有大半年了。在初步學習 React 之后就正式應用到項目中,當時就想把自己的一些想法寫出來分享一下,無奈不太會寫文章,再則時間不是很充裕,所以也就擱下了。
本篇文章比較基礎,沒有深入的分析,大神們輕看。廢話就不多說了,那么讓我們來進入正題。
簡介首先想要介紹的是 React,看到這篇文章的朋友想必都有一些關于 React 的了解了,但對于剛接觸的新人而言,在這就要簡要地介紹一下了。然后就是關于使用 React 構建一個簡單單頁應用(下文用 SPA 代替,Single Page Application)的一些介紹和講解。
關于 ReactReact 起源于 Facebook 的內部項目,因為該公司對市場上所有 JavaScript MVC 框架,都不滿意,就決定自己寫一套,用來架設Instagram 的網站。做出來以后,發現這套東西很好用,就在2013年5月開源了。(更多相關介紹請看這)
特點:
僅僅只是 UI
虛擬 DOM:最大限度減少與 DOM 的交互(類似于使用 jQuery 操作 DOM)
單向數據流:很大程度減少了重復代碼的使用
組件化:
可組合(Composeable):一個組件易于和其它組件一起使用,或者嵌套在另一個組件內部。如果一個組件內部創建了另一個組件,那么說父組件擁有(own)它創建的子組件,通過這個特性,一個復雜的UI可以拆分成多個簡單的UI組件
可重用(Reusable):每個組件都是具有獨立功能的,它可以被使用在多個UI場景
可維護(Maintainable):每個小的組件僅僅包含自身的邏輯,更容易被理解和維護
生命周期:
Mounting:已插入真實 DOM
Updating:正在被重新渲染
Unmounting:已移出真實 DOM
React 為每個狀態都提供了兩種處理函數,will 函數在進入狀態之前調用,did 函數在進入狀態之后調用,三種狀態共計五種處理函數。
componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()
此外,React 還提供兩種特殊狀態的處理函數。
componentWillReceiveProps(object nextProps):已加載組件收到新的參數時調用
shouldComponentUpdate(object nextProps, object nextState):組件判斷是否重新渲染時調用
正題那么進入正題,花了點時間去寫一個簡單的 SPA,也算是一個比較完整 React 骨架,但不包括測試(測試的教程可以看這個),相關源碼可以查看 react-start-kit。
接下來看看我們這個項目的構建需要用到些什么:
react
redux
webpack
react-router
ant design
babel
...
還有一些沒有列舉出來,具體可以看倉庫源碼的 package.json。其中的詳細介紹會在文尾列出一些我所看過的文章或是官方介紹。
配置項 Webpack說到 React 項目的構建就不得不提 Webpack 這個神器。構建工具有很多,例如 Grunt,Gulp,Brunch 等,相比這些構建工具,Webpack 感覺就是和 React 不謀而合,尤其是 react-hot-loader 這樣的神器(熱加載),讓 Webpack 成為最主流的 React 構建工具。
關于 Webpack 的特性以及介紹這里就不贅述了,我們可以從下圖看出 Webpack 的作用:
接著我們從項目代碼中來看 Webpack。
entry: { app: [__dirname + "/src/index"], }, output: { path: __dirname + "/_dist", filename: "[name]_[hash].js", }
這部分主要是指定入口和出口文件。entry 作為項目的入口文件;output 作為文件編譯后的出口,其中 path 代表輸出的路徑,filename 代表文件名稱,而 [name]_[hash] 保證了瀏覽器不會存在緩存(即修改文件后效果不生效)。
module: { loaders: [{ test: /.js$/, loaders: ["babel"], exclude: /node_modules/, }, { test: /.css$/, loaders: ["style", "css"], include: /components/, }, { test: /.(jpe?g|png|gif|svg|ico)/i, loader: "file", }, { test: /.(ttf|eot|svg|woff|woff2)/, loader: "file", }, { test: /.(pdf)/, loader: "file", }, { test: /.(swf|xap)/, loader: "file", }], }
而這部分會幫助我們去處理不同類型的文件,其中 test 就是文件的后綴,loaders 是“轉譯器”,include 是指定文件的目錄,exclude 是排除某個目錄。我們可以看出,所有的 .js 文件都會通過 babel 去轉譯,也就是我們在項目中使用 ES6+ 語法會通過 babel 轉譯成瀏覽器可以識別的 ES5 代碼。
最后配置好的 config 是這樣的:
var HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { entry: { app: [__dirname + "/src/index"], }, output: { path: __dirname + "/_dist", filename: "[name]_[hash].js", }, resolve: { root: [ __dirname + "/src", __dirname + "/node_modules", __dirname, ], extensions: ["", ".js"], }, module: { loaders: [{ test: /.js$/, loaders: ["babel"], exclude: /node_modules/, }, { test: /.css$/, loaders: ["style", "css"], include: /components/, }, { test: /.(jpe?g|png|gif|svg|ico)/i, loader: "file", }, { test: /.(ttf|eot|svg|woff|woff2)/, loader: "file", }, { test: /.(pdf)/, loader: "file", }, { test: /.(swf|xap)/, loader: "file", }], }, plugins: [ new HtmlWebpackPlugin({ template: __dirname + "/src/index.html", favicon: __dirname + "/src/favicon.ico", inject: false, }), ], };Express 服務器啟動
Node.js web 應用開發框架 Express 作為項目的 web 服務器,有 Node.js 開發經驗的同學應該挺熟悉的了,這里也不多做贅述。
最終的啟動代碼是這樣的:
var express = require("express"); var webpack = require("webpack"); var webpackConfig = require("./webpack.development"); var app = express(); var compiler = webpack(webpackConfig); app.use(require("webpack-dev-middleware")(compiler, { stats: { colors: true, }, })); app.use(require("webpack-hot-middleware")(compiler)); //熱加載 app.listen(process.env.PORT, function(err) { //在沒有端口的情況下,會自動給出一個隨機端口 if (err) { console.log(err); } });
為了方便我們的訪問,項目使用了 minihost 進行啟動,方便快捷。值得一提的是,使用 h -- npm start 命令啟動時,訪問的是項目文件夾的名稱作為鏈接,例如項目叫 myproject,那么此時可以訪問 myproject.t.t。
Redux對于復雜的 SPA,狀態(state)管理非常重要。state 可能包括:服務端的響應數據、本地對響應數據的緩存、本地創建的數據(比如,表單數據)以及一些 UI 的狀態信息(比如,路由、選中的 tab、是否顯示下拉列表、頁碼控制等等)。如果 state 變化不可預測,就會難于調試(state 不易重現,很難復現一些 bug)和不易于擴展(比如,優化更新渲染、服務端渲染、路由切換時獲取數據等等)。
state 為單一對象,使得 Redux 只需要維護一棵狀態樹,服務端很容易初始化狀態,易于服務器渲染。state 只能通過 dispatch(action) 來觸發更新,更新邏輯由 reducer 來執行。
在使用 Redux 后,state 就變得很容易維護,而且數據流非常清晰,容易解決遇到的 BUG。
我們可以看下圖來簡要地理解 Redux:
我們可以在項目中看到的結構是:
├─store ├─actions ├─reducers ├─constants ├─helpers ├─components ├─app.js ├─favicon.ico ├─index.html ├─index.js └─routes.js
最終我們的 store 是:
import {createStore, applyMiddleware, combineReducers, compose} from "redux"; import thunk from "redux-thunk"; import {reduxReactRouter} from "redux-router"; import createHistory from "history/lib/createHashHistory"; import routes from "../routes"; import * as reducers from "../reducers"; let middlewares = [thunk]; if (process.env.NODE_ENV === "development") { //在開發環境下可以看到 state 的 log const logger = require("redux-logger"); middlewares = [...middlewares, logger]; } const finalCreateStore = compose( //組合多個函數 applyMiddleware(...middlewares), reduxReactRouter({routes, createHistory}), )(createStore); //創建 store 來管理所有的 state export default function configureStore(initialState) { const reducer = combineReducers(reducers); //把一個由多個不同 reducer 函數作為 value 的 object,合并成一個最終的 reducer 函數 const store = finalCreateStore(reducer, initialState); if (process.env.NODE_ENV === "development" && module.hot) { //開發環境下的熱加載 module.hot.accept("../reducers", () => { const nextReducers = require("../reducers"); const nextReducer = combineReducers(nextReducers); store.replaceReducer(nextReducer); }); } return store; }
獲取 state 需要在組件中調用 connect 函數,可以自行定義需要獲取的 state。(這用于區分展示型和容器型組件)
... @connect( state => ({ data: state.data }) ) export default class ComponentOne extends Component { ... }
注意:connect 必須緊跟 component 的定義,不然會報錯。
Router為項目添加路由系統,使用了 react-router 來管理路由。在開發項目的時候,比較推薦的做法是使用路由去跳轉頁面,并且創建 store 的同時我們就把 router 加入其中,然后我們根據路由的變化去更新視圖。
我們可以看看路由的源碼:
import React from "react"; import Route from "react-router/lib/Route"; //import {Route} from "react-router"; import Base from "components/base/Base"; import Home from "components/home/Home"; export default ();
path 是跳轉路徑,component 是與路徑相匹配的組件。
Ant Design由螞蟻金服技術部出品的一個 UI 設計語言,也是項目中所用到的 UI 組件庫。
特性:
Designed as Ant Design,提煉和服務企業級中后臺產品的交互語言和視覺風格
React Component 上精心封裝的高質量 UI 庫
基于 npm + webpack + babel 的工作流,支持 ES2015
選擇理由:
有很好的技術支持
簡潔的樣式
基本涵蓋常用組件
...
組件作為 React 渲染的一個基本組成,我們通常把它們分為兩類,容器型和展示型。相較于容器型,展示型是通過容器型傳遞 props 來獲取數據,而容器型可以直接從 store 中獲取,處理并傳遞給下級組件。
在實際應用中會發現,定義一個容器型組件負責處理數據,然后分發給下級展示型組件,當需要更新數據時,那么容器型組件發生變化會引起下級展示型組件的變化,這樣就對我們業務上造成了一定的困擾(在不需要更新的部分組件上也發生了更新)。因此,我們選擇在需要獲取數據的組件中使用 connect,這樣則會方便很多(感覺有些違反規則)。
在項目中我們會這么定義組件:
import React, {Component} from "react"; import {connect} from "react-redux"; import Presentational from "components/common/Presentational"; @connect( state => ({ data: state.data }) ) export default class Container extends Component { render() { const {data} = this.props; return () } }
上面是可以從 store 獲取數據的組件,并嵌套另一個組件,將數據傳遞給它。
import React, {Component, PropTypes} from "react"; export default class Presentational extends Component { static propTypes = { data: PropTypes.string, } render() { const {data} = this.props; return ({data}) } }
獲取上一個組件傳遞過來的數據,并展示出來。
總結這是一篇科普文(哈哈~囧),并沒有深入去分析各項技術的具體內容,希望能幫助剛入手 React 的新手們。實踐項目的源碼可以在 react-start-kit 看到,你可以下載這個項目進行自己的一些探索和開發。還在努力探索中,文中有措辭不當或是疏漏,歡迎提出意見和建議。
參考react 官網
Babel 官網
redux 介紹
redux 中文文檔
Ant design 官網
React 入門實例教程
react-router 中文文檔
Webpack 傻瓜式指南(一)
CSS Modules 詳解及 React 中實踐
一看就懂的 ReactJs 入門教程(精華版)
深入淺出React(二):React開發神器Webpack
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78831.html
摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入匯總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業務工作時也會不定期更...
摘要:一團隊組織網站說明騰訊團隊騰訊前端團隊,代表作品,致力于前端技術的研究騰訊社交用戶體驗設計,簡稱,騰訊設計團隊網站騰訊用戶研究與體驗設計部百度前端研發部出品淘寶前端團隊用技術為體驗提供無限可能凹凸實驗室京東用戶體驗設計部出品奇舞團奇虎旗下前 一、團隊組織 網站 說明 騰訊 AlloyTeam 團隊 騰訊Web前端團隊,代表作品WebQQ,致力于前端技術的研究 ISUX 騰...
摘要:一團隊組織網站說明騰訊團隊騰訊前端團隊,代表作品,致力于前端技術的研究騰訊社交用戶體驗設計,簡稱,騰訊設計團隊網站騰訊用戶研究與體驗設計部百度前端研發部出品淘寶前端團隊用技術為體驗提供無限可能凹凸實驗室京東用戶體驗設計部出品奇舞團奇虎旗下前 一、團隊組織 網站 說明 騰訊 AlloyTeam 團隊 騰訊Web前端團隊,代表作品WebQQ,致力于前端技術的研究 ISUX 騰...
摘要:一團隊組織網站說明騰訊團隊騰訊前端團隊,代表作品,致力于前端技術的研究騰訊社交用戶體驗設計,簡稱,騰訊設計團隊網站騰訊用戶研究與體驗設計部百度前端研發部出品淘寶前端團隊用技術為體驗提供無限可能凹凸實驗室京東用戶體驗設計部出品奇舞團奇虎旗下前 一、團隊組織 網站 說明 騰訊 AlloyTeam 團隊 騰訊Web前端團隊,代表作品WebQQ,致力于前端技術的研究 ISUX 騰...
摘要:編程書籍的整理和收集最近一直在學習深度學習和機器學習的東西,發現深入地去學習就需要不斷的去提高自己算法和高數的能力然后也找了很多的書和文章,隨著不斷的學習,也整理了下自己的學習筆記準備分享出來給大家后續的文章和總結會繼續分享,先分享一部分的 編程書籍的整理和收集 最近一直在學習deep learning深度學習和機器學習的東西,發現深入地去學習就需要不斷的去提高自己算法和高數的能力然后...
閱讀 1379·2021-10-19 11:42
閱讀 723·2021-09-22 16:04
閱讀 1872·2021-09-10 11:23
閱讀 1848·2021-07-29 14:48
閱讀 1251·2021-07-26 23:38
閱讀 2817·2019-08-30 15:54
閱讀 1027·2019-08-30 11:25
閱讀 1700·2019-08-29 17:23