摘要:而函數(shù)式編程就不一樣了,這是模仿我們?nèi)祟惖乃季S方式發(fā)明出來的。數(shù)據(jù)流在中,數(shù)據(jù)的流動是單向的,即從父節(jié)點傳遞到子節(jié)點。數(shù)據(jù)流嚴(yán)格的單向數(shù)據(jù)流是架構(gòu)的設(shè)計核心。
前言
總括: 本文采用react+redux+react-router+less+es6+webpack,以實現(xiàn)一個簡易備忘錄(todolist)為例盡可能全面的講述使用react全家桶實現(xiàn)一個完整應(yīng)用的過程。
代碼地址:React全家桶實現(xiàn)一個簡易備忘錄
原文博客地址:React全家桶實現(xiàn)一個簡易備忘錄
知乎專欄&&簡書專題:前端進(jìn)擊者(知乎)&&前端進(jìn)擊者(簡書)
博主博客地址:Damonare的個人博客
人生不失意,焉能暴己知。
技術(shù)說明功能說明技術(shù)架構(gòu):本備忘錄使用react+react-router+redux+less+ES6+webpack實現(xiàn);
頁面UI參照:TodoList官網(wǎng)實現(xiàn);
在線演示地址:Damonare的備忘錄;
支持回車添加新事項;
支持刪除事項(點擊X符號);
支持狀態(tài)轉(zhuǎn)換具體包括:
新建事項->正在進(jìn)行(點擊checkbox選項)
正在進(jìn)行->已完成(點擊文字內(nèi)容本身)
正在進(jìn)行->新建事項(點擊checkbox選項)
已完成->正在進(jìn)行(點擊文字本身)
支持判斷輸入空字符,過長字符(20個漢字以內(nèi));
支持搜索;
支持本地化存儲;
支持狀態(tài)的展開隱藏(點擊標(biāo)題)
兼容手機(jī)端(iPhone6及以上)
支持路由切換
正文 1. React淺談 1.1 組件化? 毫無疑問,當(dāng)談到React的時候不能避免的會提到組件化思想。React剛開始想解決的問題只是UI這一層面的問題,也就是MVC中view層面的問題,不成想如今越滾越大,從最早的UI引擎變成了一整套前后端通吃的 Web App 解決方案。對于React組件的理解同樣要站在view層面的角度出發(fā),一個完整的頁面是由大大小小的組件堆疊而成,就好像搭積木,每一塊積木都是一個組件,組件套組件組成了用戶所能看到的完整的頁面。
1.2 JSX語法糖? 使用React,不一定非要使用JSX語法,可以使用原生的JS進(jìn)行開發(fā)。但是React作者強(qiáng)烈建議我們使用JSX,因為JSX在定義類似HTML這種樹形結(jié)構(gòu)時,十分的簡單明了。這里簡單的講下JSX的由來。
? 比如,下面一個div元素,我們用HTML語法描述為:
Test
如果換做使用javascript描述這個元素呢?最好的方式可以簡單的轉(zhuǎn)化為json對象,如下:
{ type:"div", props:{ className:"test", children:{ type:"span", props:{ children:"Test" } } } }
這樣我們就可以在javascript中創(chuàng)建一個Virtual DOM(虛擬DOM)了。當(dāng)然,這樣是沒法復(fù)用的,我們再把它封裝一下:
const Div=>({text}){ return { type:"div", props:{ className:"test", children:{ type:"span", props:{ children: text, }, }, }, } }
接下來再實現(xiàn)這個div就可以直接調(diào)用Div("Test")來創(chuàng)建。但上述結(jié)構(gòu)看起來實在讓人不爽,寫起來也很容易寫混,一旦結(jié)構(gòu)復(fù)雜了,很容易讓人找不著北,于是JSX語法應(yīng)運(yùn)而生。我們用寫HTML的方式寫這段代碼,再經(jīng)過翻譯器轉(zhuǎn)換成javascript后交給瀏覽器執(zhí)行。上述代碼用JSX重寫:
const Div =()=>(Test);
多么簡單明了!??!具體的JSX語法不多說了,學(xué)習(xí)更多戳這:JSX in Depth
1.3 Virtual DOM其實上面已經(jīng)提到了Virtual DOM,它的存在也是React長久不衰的原因之一,虛擬DOM的概念并不是FB首創(chuàng)卻在FB的手上大火了起來(后臺是多么重要)。
我們知道真實的頁面對應(yīng)了一個DOM樹,在傳統(tǒng)頁面的開發(fā)模式中,每次需要更新頁面時,都需要對DOM進(jìn)行更新,DOM操作十分昂貴,為減少對于真實DOM的操作,誕生了Virtual DOM的概念,也就是用javascript把真實的DOM樹描述了一遍,使用的也就是我們剛剛說過的JSX語法。對比如下:
每次數(shù)據(jù)更新之后,重新計算Virtual DOM,并和上一次的Virtual DOM對比,對發(fā)生的變化進(jìn)行批量更新。React也提供了shouldComponentUpdate生命周期回調(diào),來減少數(shù)據(jù)變化后不必要的Virtual DOM對比過程,提升了性能。
Virtual DOM雖然渲染方式比傳統(tǒng)的DOM操作要好一些,但并不明顯,因為對比DOM節(jié)點也是需要計算的,最大的好處在于可以很方便的和其它平臺集成,比如react-native就是基于Virtual DOM渲染出原生控件。具體渲染出的是Web DOM還是Android控件或是iOS控件就由平臺決定了。所以我們說react的出現(xiàn)是一場革命,一次對于native app的宣戰(zhàn),就像react-native那句口號——Learn Once,Write Anywhere.
1.4 函數(shù)式編程? 過去編程方式主要是以命令式編程為主,什么意思呢?簡單說電腦的思維方式和我們?nèi)祟惖乃伎挤绞绞遣灰粯拥摹N覀內(nèi)祟惖拇竽X擅長的是分析問題,提出一個解決問題的方案,電腦則是生硬的執(zhí)行指令,命令式編程就像是給電腦下達(dá)命令,讓電腦去執(zhí)行一樣,現(xiàn)在主要的編程語言(比如:Java,C,C++等)都是由命令式編程構(gòu)建起來的。
? 而函數(shù)式編程就不一樣了,這是模仿我們?nèi)祟惖乃季S方式發(fā)明出來的。例如:操作某個數(shù)組的每一個元素然后返回一個新數(shù)組,如果是計算機(jī)的思考方式,會這樣想:創(chuàng)建一個新數(shù)組=>遍歷舊數(shù)組=>給新數(shù)組賦值。如果是人類的思考方式,會這樣想:創(chuàng)建一個數(shù)組方法,作用在舊數(shù)組上,返回新數(shù)組。這樣此方法可以被重復(fù)利用。而這就是函數(shù)式編程了。
1.5 數(shù)據(jù)流在React中,數(shù)據(jù)的流動是單向的,即從父節(jié)點傳遞到子節(jié)點。也因此組件是簡單的,他們只需要從父組件獲取props渲染即可。如果頂層的props改變了,React會遞歸的向下遍歷整個組件樹,重新渲染所有使用這個屬性的組件。那么父組件如何獲取子組件數(shù)據(jù)呢?很簡單,通過回調(diào)就可以了,父組件定義某個方法供給子組件調(diào)用,子組件調(diào)用方法傳遞給父組件數(shù)據(jù),Over。
2. React-router這東西我覺得沒啥難度,官方例子都很不錯,跟著官方例子來一遍基本就明白到底是個啥玩意了,官方例子:react-router-tutorial。
完事以后可以再看一下阮一峰老師的教程,主要是對一些API的講解:React Router 使用教程。
還有啥不明白的歡迎評論留言共同探討。
3. Redux 3.1 簡介隨著 JavaScript 單頁應(yīng)用開發(fā)日趨復(fù)雜,JavaScript 需要管理比任何時候都要多的 state (狀態(tài))。 這些 state 可能包括服務(wù)器響應(yīng)、緩存數(shù)據(jù)、本地生成尚未持久化到服務(wù)器的數(shù)據(jù),也包括 UI 狀態(tài),如激活的路由,被選中的標(biāo)簽,是否顯示加載動效或者分頁器等等。如果一個 model 的變化會引起另一個 model 變化,那么當(dāng) view 變化時,就可能引起對應(yīng) model 以及另一個 model 的變化,依次地,可能會引起另一個 view 的變化。亂!
這時候Redux就強(qiáng)勢登場了,現(xiàn)在你可以把React的model看作是一個個的子民,每一個子民都有自己的一個狀態(tài),紛紛擾擾,各自維護(hù)著自己狀態(tài),我行我素,那哪行啊!太亂了,我們需要一個King來領(lǐng)導(dǎo)大家,我們就可以把Redux看作是這個King。網(wǎng)羅所有的組件組成一個國家,掌控著一切子民的狀態(tài)!防止有人叛亂生事!
這個時候就把組件分成了兩種:容器組件(King或是路由)和展示組件(子民)。
容器組件:即redux或是router,起到了維護(hù)狀態(tài),出發(fā)action的作用,其實就是King高高在上下達(dá)指令。
展示組件:不維護(hù)狀態(tài),所有的狀態(tài)由容器組件通過props傳給他,所有操作通過回調(diào)完成。
展示組件 | 容器組件 | |
---|---|---|
作用 | 描述如何展現(xiàn)(骨架、樣式) | 描述如何運(yùn)行(數(shù)據(jù)獲取、狀態(tài)更新) |
直接使用 Redux | 否 | 是 |
數(shù)據(jù)來源 | props | 監(jiān)聽 Redux state |
數(shù)據(jù)修改 | 從 props 調(diào)用回調(diào)函數(shù) | 向 Redux 派發(fā) actions |
調(diào)用方式 | 手動 | 通常由 React Redux 生成 |
Redux三大部分:store,action,reducer。相當(dāng)于King的直系下屬。
那么也可以看出Redux只是一個狀態(tài)管理方案,完全可以多帶帶拿出來使用,這個King不僅僅可以是React的,去Angular,Ember那里也是可以做King的。在React中維系King和組件關(guān)系的庫叫做?react-redux。
, 它主要有提供兩個東西:Provider 和 connect,具體使用文后說明。
提供幾個Redux的學(xué)習(xí)地址:官方教程-中文版,Redux 入門教程(一):基本用法
3.2 StoreStore 就是保存數(shù)據(jù)的地方,它實際上是一個Object tree。整個應(yīng)用只能有一個 Store。這個Store可以看做是King的首相,掌控一切子民(組件)的活動(state)。
Redux 提供createStore這個函數(shù),用來生成 Store。
import { createStore } from "redux"; const store = createStore(func);
createStore接受一個函數(shù)作為參數(shù),返回一個Store對象(首相誕生記)
我們來看一下Store(首相)的職責(zé):
維持應(yīng)用的 state;
提供?getState()?方法獲取 state;
提供?dispatch(action)?方法更新 state;
通過?subscribe(listener)?注冊監(jiān)聽器;
通過?subscribe(listener)?返回的函數(shù)注銷監(jiān)聽器。
3.3 actionState 的變化,會導(dǎo)致 View 的變化。但是,用戶接觸不到 State,只能接觸到 View。所以,State 的變化必須是 View 導(dǎo)致的。Action 就是 View 發(fā)出的通知,表示 State 應(yīng)該要發(fā)生變化了。即store的數(shù)據(jù)變化來自于用戶操作。action就是一個通知,它可以看作是首相下面的郵遞員,通知子民(組件)改變狀態(tài)。它是 store 數(shù)據(jù)的唯一來源。一般來說會通過?store.dispatch()?將 action 傳到 store。
Action 是一個對象。其中的type屬性是必須的,表示 Action 的名稱。
const action = { type: "ADD_TODO", payload: "Learn Redux" };
Action創(chuàng)建函數(shù)
Action 創(chuàng)建函數(shù)?就是生成 action 的方法?!癮ction” 和 “action 創(chuàng)建函數(shù)” 這兩個概念很容易混在一起,使用時最好注意區(qū)分。
在 Redux 中的 action 創(chuàng)建函數(shù)只是簡單的返回一個 action:
function addTodo(text) { return { type: ADD_TODO, text } }
這樣做將使 action 創(chuàng)建函數(shù)更容易被移植和測試。
3.4 reducerAction?只是描述了有事情發(fā)生了這一事實,并沒有指明應(yīng)用如何更新 state。而這正是 reducer 要做的事情。也就是郵遞員(action)只負(fù)責(zé)通知,具體你(組件)如何去做,他不負(fù)責(zé),這事情只能是你們村長(reducer)告訴你如何去做才能符合社會主義核心價值觀,如何做才能對建設(shè)共產(chǎn)主義社會有利。
專業(yè)解釋: Store 收到 Action 以后,必須給出一個新的 State,這樣 View 才會發(fā)生變化。這種 State 的計算過程就叫做 Reducer。
Reducer 是一個函數(shù),它接受 Action 和當(dāng)前 State 作為參數(shù),返回一個新的 State。
const reducer = function (state, action) { // ... return new_state; };3.5 數(shù)據(jù)流
嚴(yán)格的單向數(shù)據(jù)流是 Redux 架構(gòu)的設(shè)計核心。
Redux 應(yīng)用中數(shù)據(jù)的生命周期遵循下面 4 個步驟:
調(diào)用?store.dispatch(action)。
Redux store 調(diào)用傳入的 reducer 函數(shù)。
根 reducer 應(yīng)該把多個子 reducer 輸出合并成一個單一的 state 樹。
Redux store 保存了根 reducer 返回的完整 state 樹。
工作流程圖如下:
3.6 Connect這里需要再強(qiáng)調(diào)一下:Redux 和 React 之間沒有關(guān)系。Redux 支持 React、Angular、Ember、jQuery 甚至純 JavaScript。
盡管如此,Redux 還是和?React?和?Deku?這類框架搭配起來用最好,因為這類框架允許你以 state 函數(shù)的形式來描述界面,Redux 通過 action 的形式來發(fā)起 state 變化。
Redux 默認(rèn)并不包含?React 綁定庫,需要多帶帶安裝。
npm install --save react-redux
當(dāng)然,我們這個實例里是不需要的,所有需要的依賴已經(jīng)在package.json里配置好了。
React-Redux 提供connect方法,用于從 UI 組件生成容器組件。connect的意思,就是將這兩種組件連起來。
import { connect } from "react-redux"; const TodoList = connect()(Memos);
上面代碼中Memos是個UI組件,TodoList就是由 React-Redux 通過connect方法自動生成的容器組件。
而只是純粹的這樣把Memos包裹起來毫無意義,完整的connect方法這樣使用:
import { connect } from "react-redux" const TodoList = connect( mapStateToProps )(Memos)
上面代碼中,connect方法接受兩個參數(shù):mapStateToProps和mapDispatchToProps。它們定義了 UI 組件的業(yè)務(wù)邏輯。前者負(fù)責(zé)輸入邏輯,即將state映射到 UI 組件的參數(shù)(props),后者負(fù)責(zé)輸出邏輯,即將用戶對 UI 組件的操作映射成 Action。
3.7 Provider?這個Provider 其實是一個中間件,它是為了解決讓容器組件拿到King的指令(state對象)而存在的。
import { Provider } from "react-redux" import { createStore } from "redux" import todoApp from "./reducers" import App from "./components/App" let store = createStore(todoApp); render(, document.getElementById("root") )
上面代碼中,Provider在根組件外面包了一層,這樣一來,App的所有子組件就默認(rèn)都可以拿到state了。
4.實戰(zhàn)備忘錄講解之前可以先看一下github上的代碼,你可以clone下來學(xué)習(xí),也可以在線給我提issue,歡迎戳這:React全家桶實現(xiàn)簡易備忘錄
4.1目錄結(jié)構(gòu). ├── app #開發(fā)目錄 | | | ├──actions #action的文件 | | | ├──components #展示組件 | | | ├──containers #容器組件,主頁 | | | ├──reducers #reducer文件 | | | |——routes #路由文件,容器組件 | | | |——static #靜態(tài)文件 | | | ├──stores #store配置文件 | | | |——main.less #路由樣式 | | | └──main.js #入口文件 | ├── build #發(fā)布目錄 ├── node_modules #包文件夾 ├── .gitignore ├── .jshintrc ├── webpack.production.config.js #生產(chǎn)環(huán)境配置 ├── webpack.config.js #webpack配置文件 ├── package.json #環(huán)境配置 └── README.md #使用說明
接下來,我們只關(guān)注app目錄就好了。
4.2入口文件import React from "react"; import ReactDOM from "react-dom"; import {Route, IndexRoute, browserHistory, Router} from "react-router"; import {createStore} from "redux"; import {Provider} from "react-redux"; import App from "./container/App"; import AllMemosRoute from "./routes/AllMemosRoute"; import TodoRoute from "./routes/TodoRoute"; import DoingRoute from "./routes/DoingRoute"; import DoneRoute from "./routes/DoneRoute"; import configureStore from "./stores"; import "./main.less"; const store = configureStore(); ReactDOM.render(, document.body.appendChild(document.createElement("div")))
這里我們從 react-redux 中獲取到 Provider 組件,我們把它渲染到應(yīng)用的最外層。
他需要一個屬性 store ,他把這個 store 放在context里,給Router(connect)用。
app/store/index.jsx
import { createStore } from "redux"; import reducer from "../reducers"; export default function configureStore(initialState) { const store = createStore(reducer, initialState); if (module.hot) { // Enable Webpack hot module replacement for reducers module.hot.accept("../reducers", () => { const nextReducer = require("../reducers"); store.replaceReducer(nextReducer); }); } return store; }4.4 Action 創(chuàng)建函數(shù)和常量
app/action/index.jsx
"use strict"; /* * @author Damonare 2016-12-10 * @version 1.0.0 * action 類型 */ export const Add_Todo = "Add_Todo"; export const Change_Todo_To_Doing = "Change_Todo_To_Doing"; export const Change_Doing_To_Done = "Change_Doing_To_Done"; export const Change_Done_To_Doing = "Change_Done_To_Doing"; export const Change_Doing_To_Todo = "Change_Doing_To_Todo"; export const Search="Search"; export const Delete_Todo="Delete_Todo"; /* * action 創(chuàng)建函數(shù) * @method addTodo添加新事項 * @param {String} text 添加事項的內(nèi)容 */ export function addTodo(text) { return { type: Add_Todo, text } } /* * @method search 查找事項 * @param {String} text 查找事項的內(nèi)容 */ export function search(text) { return { type: Search, text } } /* * @method changeTodoToDoing 狀態(tài)由todo轉(zhuǎn)為doing * @param {Number} index 需要改變狀態(tài)的事項的下標(biāo) */ export function changeTodoToDoing(index) { return { type: Change_Todo_To_Doing, index } } /* * @method changeDoneToDoing 狀態(tài)由done轉(zhuǎn)為doing * @param {Number} index 需要改變狀態(tài)的事項的下標(biāo) */ export function changeDoneToDoing(index) { return { type: Change_Done_To_Doing, index } } /* * @method changeDoingToTodo 狀態(tài)由doing轉(zhuǎn)為todo * @param {Number} index 需要改變狀態(tài)的事項的下標(biāo) */ export function changeDoingToTodo(index) { return { type: Change_Doing_To_Todo, index } } /* * @method changeDoingToDone 狀態(tài)由doing轉(zhuǎn)為done * @param {Number} index 需要改變狀態(tài)的事項的下標(biāo) */ export function changeDoingToDone(index) { return { type: Change_Doing_To_Done, index } } /* * @method deleteTodo 刪除事項 * @param {Number} index 需要刪除的事項的下標(biāo) */ export function deleteTodo(index) { return { type: Delete_Todo, index } }
在聲明每一個返回 action 函數(shù)的時候,我們需要在頭部聲明這個 action 的 type,以便好組織管理。
每個函數(shù)都會返回一個 action 對象,所以在 容器組件里面調(diào)用
text => dispatch(addTodo(text))
就是調(diào)用dispatch(action)?。
4.5 Reducersapp/reducers/index.jsx
import { combineReducers } from "redux"; import todolist from "./todos"; // import visibilityFilter from "./visibilityFilter"; const reducer = combineReducers({ todolist }); export default reducer;
app/reducers/todos.jsx
import { Add_Todo, Delete_Todo, Change_Todo_To_Doing, Change_Doing_To_Done, Change_Doing_To_Todo, Change_Done_To_Doing, Search } from "../actions"; let todos; (function() { if (localStorage.todos) { todos = JSON.parse(localStorage.todos) } else { todos = [] } })(); function todolist(state = todos, action) { switch (action.type) { /* * 添加新的事項 * 并進(jìn)行本地化存儲 * 使用ES6展開運(yùn)算符鏈接新事項和舊事項 * JSON.stringify進(jìn)行對象深拷貝 */ case Add_Todo: localStorage.setItem("todos", JSON.stringify([ ...state, { todo: action.text, istodo: true, doing: false, done: false } ])); return [ ...state, { todo: action.text, istodo: true, doing: false, done: false } ]; /* * 將todo轉(zhuǎn)為doing狀態(tài),注意action.index的類型轉(zhuǎn)換 */ case Change_Todo_To_Doing: localStorage.setItem("todos", JSON.stringify([ ...state.slice(0, action.index), { todo:state[action.index].todo, istodo: false, doing: true, done: false }, ...state.slice(parseInt(action.index) + 1) ])); return [ ...state.slice(0, action.index), { todo:state[action.index].todo, istodo: false, doing: true, done: false }, ...state.slice(parseInt(action.index) + 1) ]; /* * 將doing轉(zhuǎn)為done狀態(tài) */ case Change_Doing_To_Done: localStorage.setItem("todos", JSON.stringify([ ...state.slice(0, action.index), { todo:state[action.index].todo, istodo: false, doing: false, done: true }, ...state.slice(parseInt(action.index) + 1) ])); return [ ...state.slice(0, action.index), { todo:state[action.index].todo, istodo: false, doing: false, done: true }, ...state.slice(parseInt(action.index) + 1) ]; /* * 將done轉(zhuǎn)為doing狀態(tài) */ case Change_Done_To_Doing: localStorage.setItem("todos", JSON.stringify([ ...state.slice(0, action.index), { todo:state[action.index].todo, istodo: false, doing: true, done: false }, ...state.slice(parseInt(action.index) + 1) ])); return [ ...state.slice(0, action.index), { todo:state[action.index].todo, istodo: false, doing: true, done: false }, ...state.slice(parseInt(action.index) + 1) ]; /* * 將doing轉(zhuǎn)為todo狀態(tài) */ case Change_Doing_To_Todo: localStorage.setItem("todos", JSON.stringify([ ...state.slice(0, action.index), { todo:state[action.index].todo, istodo: true, doing: false, done: false }, ...state.slice(parseInt(action.index) + 1) ])); return [ ...state.slice(0, action.index), { todo:state[action.index].todo, istodo: true, doing: false, done: false }, ...state.slice(parseInt(action.index) + 1) ]; /* * 刪除某個事項 */ case Delete_Todo: localStorage.setItem("todos", JSON.stringify([ ...state.slice(0, action.index), ...state.slice(parseInt(action.index) + 1) ])); return [ ...state.slice(0, action.index), ...state.slice(parseInt(action.index) + 1) ]; /* * 搜索 */ case Search: let text=action.text; let reg=eval("/"+text+"/gi"); return state.filter(item=> item.todo.match(reg)); default: return state; } } export default todolist;
具體的展示組件這里就不羅列代碼了,感興趣的可以戳這:備忘錄展示組件地址
后記嚴(yán)格來說,這個備忘錄并不是使用的react全家桶,畢竟還有一部分less代碼,不過這一個應(yīng)用也算是比較全面的使用了react+react-router+redux,作為react全家桶技術(shù)學(xué)習(xí)的練手的小項目再適合不過了。如果您對這個小東西感興趣,歡迎戳這:React全家桶實現(xiàn)簡易備忘錄給個star。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/86577.html
摘要:最近練手開發(fā)了一個項目,是一個聊天室應(yīng)用。由于我們的項目是一個單頁面應(yīng)用,因此只需要統(tǒng)一打包出一個和一個。而就是基于實現(xiàn)的一套基于事件訂閱與發(fā)布的通信庫。比如說,某一個端口了,而如果端口訂閱了,那么在端,對應(yīng)的回調(diào)函數(shù)就會被執(zhí)行。 最近練手開發(fā)了一個項目,是一個聊天室應(yīng)用。項目雖不大,但是使用到了react, react-router, redux, socket.io,后端開發(fā)使用了...
摘要:相關(guān)配置請參考中文文檔。關(guān)于的更多使用方法及理解需要詳細(xì)具體講解,涉及篇幅較大,本文暫不涉及,有興趣可以看文檔中文文檔,我會整理后再單獨章節(jié)分享接下來我們將編寫路由組件這與有一些差別,原來的方法已經(jīng)不再使用,在中或組件從中引入。 ??????相信很多剛?cè)肟覴eact的小伙伴們有一個同樣的疑惑,由于React相關(guān)庫不斷的再進(jìn)行版本迭代,網(wǎng)上很多以前的技術(shù)分享變得不再適用。比如react-...
摘要:序列文章從項目中由淺入深的學(xué)習(xí)微信小程序和快應(yīng)用前言從和原生兩個項目來介紹的使用搞懂這兩個項目上手?jǐn)]代碼篇效果圖項目歡迎技術(shù)棧路由版本狀態(tài)管理組件字體適配方案適配技能點分析技能點對應(yīng)的種定義組件方法函數(shù)式定義的無狀態(tài)組 showImg(https://segmentfault.com/img/bVbqPvN?w=820&h=512); 序列文章 從項目中由淺入深的學(xué)習(xí)vue,微信小程序...
摘要:更多相關(guān)介紹請看這特點僅僅只是虛擬最大限度減少與的交互類似于使用操作單向數(shù)據(jù)流很大程度減少了重復(fù)代碼的使用組件化可組合一個組件易于和其它組件一起使用,或者嵌套在另一個組件內(nèi)部。在使用后,就變得很容易維護(hù),而且數(shù)據(jù)流非常清晰,容易解決遇到的。 歡迎移步我的博客閱讀:《React 入門實踐》 在寫這篇文章之前,我已經(jīng)接觸 React 有大半年了。在初步學(xué)習(xí) React 之后就正式應(yīng)用到項...
摘要:希望大家在這浮夸的前端圈里,保持冷靜,堅持每天花分鐘來學(xué)習(xí)與思考。 今天的React題沒有太多的故事…… 半個月前出了248個Vue的知識點,受到很多朋友的關(guān)注,都強(qiáng)烈要求再出多些React相前的面試題,受到大家的邀請,我又找了20多個React的使用者,他們給出了328道React的面試題,由我整理好發(fā)給大家,同時發(fā)布在了前端面試每日3+1的React專題,希望對大家有所幫助,同時大...
閱讀 3498·2021-11-25 09:43
閱讀 2665·2021-09-22 15:54
閱讀 623·2019-08-30 15:55
閱讀 1004·2019-08-30 15:55
閱讀 2028·2019-08-30 15:55
閱讀 1770·2019-08-30 15:53
閱讀 3495·2019-08-30 15:52
閱讀 2066·2019-08-30 12:55