Redux和Mobx的選擇問題:讓你不再困惑!

 我在去年大量的使用了 Redux,但我最近都在使用 Mobx 來做狀態(tài)(state)管理。似乎現(xiàn)在社區(qū)里關(guān)于該選什么來替代 Redux 很自然地成為了一件困惑的事。開發(fā)者不確定該選擇哪種解決方案。這個(gè)問題并不只是出現(xiàn)在 Redux 與 Mobx 上。無論何時(shí),只要存在選擇,人們就會(huì)好奇最好的解決問題的方式是什么。我現(xiàn)在寫的這些是為了解決 Redux 和 Mobx 這兩個(gè)狀態(tài)管理庫之間的困惑。

成都創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括豐臺(tái)網(wǎng)站建設(shè)、豐臺(tái)網(wǎng)站制作、豐臺(tái)網(wǎng)頁制作以及豐臺(tái)網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,豐臺(tái)網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到豐臺(tái)省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

大部分的文章都用 React 來介紹 Mobx 和 Redux 的用法。但是在大部分情況下你都可以將 React 替換成 Angular 、 Vue 或其他。

在 2016 年年初的時(shí)候我用 React + Redux 寫了一個(gè)相當(dāng)大的應(yīng)用。在我發(fā)現(xiàn)可以使用 Mobx 替代 Redux 時(shí),我花時(shí)間將應(yīng)用從 Redux 重構(gòu)成了 Mobx ?,F(xiàn)在我可以非常自在的使用它倆并且解釋它倆的用法。

這篇文章將要講什么呢?如果你不打算看這么長的文章(TLDR:too long, didn't read(查看此鏈接請自備梯子)),你可以看下目錄。但我想給你更多細(xì)節(jié):第一,我想簡單地回顧狀態(tài)管理庫為我們解決了什么問題。畢竟我們寫 React 時(shí)只用 setState() 或?qū)懫渌?SPA 框架時(shí)用 setState() 類似的方法一樣也可以做的不錯(cuò)。第二,我會(huì)大致的說下它們之間的相同之處和不同之處。第三,我會(huì)給 React 生態(tài)初學(xué)者指明怎樣學(xué)習(xí) React 的狀態(tài)管理。友情提醒:在你深入 Mobx 和 Redux 之前,請先使用 setState() 。最后,如果你已經(jīng)有一個(gè)使用了 Mobx 或 Redux 的應(yīng)用,我將會(huì)就如何從其中一個(gè)狀態(tài)管理庫重構(gòu)到另一個(gè)給你更多我的理解。

目錄

我們要解決的是什么問題?

Mobx 和 Redux 的不同?

React 狀態(tài)管理的學(xué)習(xí)曲線

嘗試另一個(gè)狀態(tài)管理方案?

最后思考

我們要解決的是什么問題?

所有人都想在應(yīng)用中使用狀態(tài)管理。但它為我們解決了什么問題?很多人開始一個(gè)小應(yīng)用時(shí)就已經(jīng)引入一個(gè)狀態(tài)管理庫。所有人都在談?wù)?Mobx 和 Redux ,不是嗎?但大部分應(yīng)用在一開始的時(shí)候并不需要大型的狀態(tài)管理。這甚至是危險(xiǎn)的,因?yàn)檫@部分人將無法體驗(yàn) Mobx 和 Redux 這些庫所要解決的問題。

如今的現(xiàn)狀是要用組件(components)來構(gòu)建一個(gè)前端應(yīng)用。組件有自己的內(nèi)部狀態(tài)。舉個(gè)栗子,在 React 中上述的本地狀態(tài)是用this.state和setState()來處理。但本地狀態(tài)的狀態(tài)管理在膨脹的應(yīng)用中很快會(huì)變得混亂,因?yàn)椋?/p>

一個(gè)組件需要和另一個(gè)組件共享狀態(tài)

一個(gè)組件需要改變另一個(gè)組件的狀態(tài)

到一定程度時(shí),推算應(yīng)用的狀態(tài)將會(huì)變得越來越困難。它就會(huì)變成一個(gè)有很多狀態(tài)對象并且在組件層級上互相修改狀態(tài)的混亂應(yīng)用。在大部分情況下,狀態(tài)對象和狀態(tài)的修改并沒有必要綁定在一些組件上。當(dāng)你把狀態(tài)提升時(shí),它們可以通過組件樹得到。

所以,解決方案是引入狀態(tài)管理庫,比如:Mobx 或 Redux。它提供工具在某個(gè)地方保存狀態(tài)、修改狀態(tài)和更新狀態(tài)。你可以從一個(gè)地方獲得狀態(tài),一個(gè)地方修改它,一個(gè)地方得到它的更新。它遵循單一數(shù)據(jù)源的原則。這讓我們更容易推斷狀態(tài)的值和狀態(tài)的修改,因?yàn)樗鼈兣c我們的組件是解耦的。

像 Redux 和 Mobx 這類狀態(tài)管理庫一般都有附帶的工具,例如在 React 中使用的有 react-redux 和 mobx-react,它們使你的組件能夠獲得狀態(tài)。一般情況下,這些組件被叫做容器組件(container components),或者說的更加確切的話,就是連接組件( connected components )。只要你將組件升級成連接組件,你就可以在組件層級的任何地方得到和更改狀態(tài)。

Mobx 和 Redux 的不同?

在我們深入了解 Redux 和 Mobx 的不同之前,我想先談?wù)勊鼈冎g的相同之處。

這兩個(gè)庫都是用來管理 JavaScript 應(yīng)用的狀態(tài)。它們并不一定要跟 React 綁定在一起,它們也可以在 AngularJs 和 VueJs 這些其他庫里使用。但它們與 React 的理念結(jié)合得非常好。

如果你選擇了其中一個(gè)狀態(tài)管理方案,你不會(huì)感到被它鎖定了。因?yàn)槟憧梢栽谌魏螘r(shí)候切換到另一個(gè)解決方案。你可以從 Mobx 換成 Redux 或從 Redux 換成 Mobx。我下面會(huì)展示如何能夠做到。

Dan Abramov 的 Redux 是從 flux 架構(gòu)派生出來的。和 flux 不同的是,Redux 用單一 store 而不是多個(gè) store 來保存 state,另外,它用純函數(shù)替代 dispatcher 來修改 state,如果你對 flux 不熟并且沒接觸過狀態(tài)管理,不要被這段內(nèi)容所煩惱。

Redux 被 FP(函數(shù)式編程)原則所影響。FP 可以在 JavaScript 中使用,但很多人有面向?qū)ο笳Z言的背景,比如 Java。他們在剛開始的時(shí)候很難適應(yīng)函數(shù)式編程的原則。這就是為什么對于初學(xué)者來說 Mobx 可能更加簡單。

既然 Redux 擁抱 FP,那它使用的就是純函數(shù)。一個(gè)接受輸入并返回輸出并且沒有其他依賴的純函數(shù)。一個(gè)純函數(shù)在相同的輸入下輸出總是相同而且沒有任何副作用。

(state, action) => newState

你的 Redux state 是不可變的,你應(yīng)該總是返回一個(gè)新的 state 而不是修改原 state。你不應(yīng)該執(zhí)行 state 的修改或依據(jù)對象引用的更改。

// don't do this in Redux, because it mutates the array
function addAuthor(state, action) {
 return state.authors.push(action.author);
}
// stay immutable and always return a new object
function addAuthor(state, action) {
 return [ ...state.authors, action.author ];
}

最后,在 Redux 的習(xí)慣用法里,state 的格式是像數(shù)據(jù)庫一樣標(biāo)準(zhǔn)化的。實(shí)體之間只靠 id 互相引用,這是最佳實(shí)踐。雖然不是每個(gè)人都這樣做,你也可以使用 normalizr 來使 state 標(biāo)準(zhǔn)化。標(biāo)準(zhǔn)化的 state 讓你能夠保持一個(gè)扁平的 state 和保持實(shí)體為單一數(shù)據(jù)源。

{
 post: {
 id: 'a',
 authorId: 'b',
 ...
 },
 author: {
 id: 'b',
 postIds: ['a', ...],
 ...
 }
}

Michel Weststrate 的 Mobx 則是受到面向?qū)ο缶幊毯晚憫?yīng)式編程的影響。它將 state 包裝成可觀察的對象,因此你的 state 就有了 Observable 的所有能力。state 數(shù)據(jù)可以只有普通的 setter 和 getter,但 observable 讓我們能在數(shù)據(jù)改變的時(shí)候得到更新的值。

Mobx 的 state 是可變的,所以你直接的修改 state :

function addAuthor(author) {
 this.authors.push(author);
}

除此之外,state 實(shí)體保持嵌套的數(shù)據(jù)結(jié)構(gòu)來互相關(guān)聯(lián)。你不必標(biāo)準(zhǔn)化 state,而是讓它們保持嵌套。

{
 post: {
 id: 'a',
 ...
 author: {
 id: 'b',
 ...
 }
 }
}

單 store 與多 stores

在 Redux 中,你將所有的 state 都放在一個(gè)全局的 store。這個(gè) store 對象就是你的單一數(shù)據(jù)源。另一方面,多個(gè) reducers 允許你修改不可變的 state。

Mobx 則相反,它使用多 stores。和 Redux 的 reducers 類似,你可以在技術(shù)層面或領(lǐng)域進(jìn)行分治。也許你想在不同的 stores 里保存你的領(lǐng)域?qū)嶓w,但仍然保持對視圖中 state 的控制。畢竟你配置 state 是為了讓應(yīng)用看起來更合理。

從技術(shù)層面來說,你一樣可以在 Redux 中使用多個(gè) stores。沒有人強(qiáng)迫你只能只用一個(gè) store。 但那不是 Redux 建議的用法。因?yàn)槟沁`反了最佳實(shí)踐。在 Redux 中,你的單 store 通過 reducers 的全局事件來響應(yīng)更新。

如何使用?

你需要跟隨下面的代碼學(xué)習(xí)使用 Redux,首先在全局 state 上新增一個(gè) user 數(shù)組。你可以看到我通過對象擴(kuò)展運(yùn)算符來返回一個(gè)新對象。你同樣可以在 ES6(原文為 ES5,實(shí)際是應(yīng)該是 ES6)中使用 Object.assign() 來操作不可變對象。

const initialState = {
 users: [
 {
 name: 'Dan'
 },
 {
 name: 'Michel'
 }
 ]
};
// reducer
function users(state = initialState, action) {
 switch (action.type) {
 case 'USER_ADD':
 return { ...state, users: [ ...state.users, action.user ] };
 default:
 return state;
 }
}
// action
{ type: 'USER_ADD', user: user };

你必須使用 dispatch({ type: 'USER_ADD', user: user });來為全局 state 添加一個(gè)新 user 。

在 Mobx 中,一個(gè) store 只管理一個(gè)子 state(就像 Redux 中管理子 state 的 reducer),但你可以直接修改 state 。

@observable 讓我們可以觀察到 state 的變化。

class UserStore {
 @observable users = [
 {
 name: 'Dan'
 },
 {
 name: 'Michel'
 }
 ];
}

現(xiàn)在我們就可以調(diào)用 store 實(shí)例的方法:userStore.users.push(user);。這是一種最佳實(shí)踐,雖然使用 actions 去操作 state 的修改更加清楚明確。

class UserStore {
 @observable users = [
 {
 name: 'Dan'
 },
 {
 name: 'Michel'
 }
 ];
 @action addUser = (user) => {
 this.users.push(user);
 }
}

在 Mobx 中你可以加上 useStrict() 來強(qiáng)制使用 action?,F(xiàn)在你可以調(diào)用 store 實(shí)例上的方法:userStore.addUser(user); 來修改你的 state 。

你已經(jīng)看到如何在 Redux 和 Mobx 中更新 state 。它們是不同的,Redux 中 state 是只讀的,你只能使用明確的 actions 來修改 state ,Mobx 則相反,state 是可讀和寫的,你可以不使用 actions 直接修改 state,但你可以 useStrict() 來使用明確的 actions 。

React 狀態(tài)管理的學(xué)習(xí)曲線

React 應(yīng)用廣泛使用 Redux 和 Mobx 。但它們是獨(dú)立的狀態(tài)管理庫,可以運(yùn)用在除 React 的任何地方。它們的互操作庫讓我們能簡單的連接React 組件。Redux + React 的 react-redux 和 MobX + React 的mobx-react 。稍后我會(huì)說明它倆如何在 React 組件樹中使用。

在最近的討論中,人們在爭論 Redux 的學(xué)習(xí)曲線。這通常發(fā)生在下面的情境中:想使用 Redux 做狀態(tài)管理的 React 初學(xué)者。大部分人認(rèn)為 React 和 Redux 本身都有頗高的學(xué)習(xí)曲線,兩者結(jié)合的話會(huì)失控。一個(gè)替代的選擇就是 Mobx ,因?yàn)樗m合初學(xué)者。

然而,我會(huì)建議 React 的初學(xué)者一個(gè)學(xué)習(xí)狀態(tài)管理的新方法。先學(xué)習(xí)React 組件內(nèi)部的狀態(tài)管理功能。在 React 應(yīng)用,你首先會(huì)學(xué)到生命周期方法,而且你會(huì)用 setState() 和 this.state 解決本地的狀態(tài)管理。我非常推薦上面的學(xué)習(xí)路徑。不然你會(huì)在 React 的生態(tài)中迷失。在這條學(xué)習(xí)路徑的最后,你會(huì)認(rèn)識(shí)到組件內(nèi)部管理狀態(tài)難度越來越大。畢竟那是 The Road to learn React 書里如何教授 React 狀態(tài)管理的方法。

現(xiàn)在我們重點(diǎn)討論 Redux 和 Mobx 為我們解決了什么問題?它倆都提供了在組件外部管理應(yīng)用狀態(tài)的方法。state 與組件相互解耦,組件可以讀取 state ,修改 state ,有新 state 時(shí)更新。這個(gè) state 是單一數(shù)據(jù)源。

現(xiàn)在你需要選擇其中一個(gè)狀態(tài)管理庫。這肯定是要第一時(shí)間解決的問題。此外,在開發(fā)過相當(dāng)大的應(yīng)用之后,你應(yīng)該能很自如使用 React 。

初學(xué)者用 Redux 還是 Mobx ?

一旦你對 React 組件和它內(nèi)部的狀態(tài)管理熟悉了,你就能選擇出一個(gè)狀態(tài)管理庫來解決你的問題。在我兩個(gè)庫都用過后,我想說 Mobx 更適合初學(xué)者。我們剛才已經(jīng)看到 Mobx 只要更少的代碼,甚至它可以用一些我們現(xiàn)在還不知道的魔法注解。
用 Mobx 你不需要熟悉函數(shù)式編程。像“不可變”之類的術(shù)語對你可能依然陌生。函數(shù)式編程是不斷上升的范式,但對于大部分 JavaScript 開發(fā)者來說是新奇的。雖然它有清晰的趨勢,但并非所有人都有函數(shù)式編程的背景,有面向?qū)ο蟊尘暗拈_發(fā)者可能會(huì)更加容易適應(yīng) Mobx 的原則。

   注:Mobx 可以很好的在 React 內(nèi)部組件狀態(tài)管理中代替 setState,我還是建議繼續(xù)使用 setState() 管理內(nèi)部狀態(tài)。但鏈接文章很清楚的說明了在 React 中用 Mobx 完成內(nèi)部狀態(tài)管理是很容易的。                                                                      

規(guī)模持續(xù)增長的應(yīng)用

在 Mobx 中你改變注解過的對象,組件就會(huì)更新。Mobx 比 Redux 使用了更多的內(nèi)部魔法實(shí)現(xiàn),因此在剛開始的時(shí)候只要更少的代碼。有 Angular 背景的會(huì)覺得跟雙向綁定很像。你在一個(gè)地方保存 state ,通過注解觀察 state ,一旦 state 修改組件會(huì)自動(dòng)的更新。

Mobx 允許直接在組件樹上直接修改 state 。

// component
<button onClick={() => store.users.push(user)} />

更好的方式是用 store 的 @action 。

// component
<button onClick={() => store.addUser(user)} />
// store
@action addUser = (user) => {
 this.users.push(user);
}

用 actions 修改 state 更加明確。上面也提到過,有個(gè)小功能可以強(qiáng)制的使用 actions 修改 state 。

// root file
import { useStrict } from 'mobx';
useStrict(true);

這樣的話第一個(gè)例子中直接修改 store 中的 state 就不再起作用了。前面的例子展示了怎樣擁抱 Mobx 的最佳實(shí)踐。此外,一旦你只用 actions ,你就已經(jīng)使用了 Redux 的約束。

在快速啟動(dòng)一個(gè)項(xiàng)目時(shí),我會(huì)推薦使用 Mobx ,一旦應(yīng)用開始變得越來越大,越來越多的人開發(fā)時(shí),遵循最佳實(shí)踐就很有意義,如使用明確的 actions 。這是擁抱 Redux 的約束:你永遠(yuǎn)不能直接修改 state ,只能使用 actions 。

遷移到 Redux

一旦應(yīng)用開始變得越來越大,越來越多的人開發(fā)時(shí),你應(yīng)該考慮使用 Redux 。它本身強(qiáng)制使用明確的 actions 修改 state 。action 有 type 和 payload 參數(shù),reducer 可以用來修改 state 。這樣的話,一個(gè)團(tuán)隊(duì)里的開發(fā)人員可以很簡單的推斷 state 的修改。

// reducer
(state, action) => newState

Redux 提供狀態(tài)管理的整個(gè)架構(gòu),并有清晰的約束規(guī)則。這是 Redux 的成功故事。

另一個(gè) Redux 的優(yōu)勢是在服務(wù)端使用。因?yàn)槲覀兪褂玫氖羌?JavaScript ,它可以在網(wǎng)絡(luò)上傳輸 state 。序列化和反序列化一個(gè) state 對象是直接可用的。當(dāng)然 Mobx 也是一樣可以的。

Mobx 是無主張的,但你可以通過 useStrict() 像 Redux 一樣使用清晰的約束規(guī)則。這就是我為什么沒說你不能在擴(kuò)張的應(yīng)用中使用 Mobx ,但 Redux 是有明確的使用方式的。而 Mobx 甚至在文檔中說:“ Mobx 不會(huì)告訴你如何組織代碼,哪里該存儲(chǔ) state 或 怎么處理事件?!彼蚤_發(fā)團(tuán)隊(duì)首先要確定 state 的管理架構(gòu)。

狀態(tài)管理的學(xué)習(xí)曲線并不是很陡峭。我們總結(jié)下建議:React 初學(xué)者首先學(xué)習(xí)恰當(dāng)?shù)氖褂?setState() 和 this.state 。一段時(shí)間之后你將會(huì)意識(shí)到在 React 應(yīng)用中僅僅使用 setState() 管理狀態(tài)的問題。當(dāng)你尋找解決方案時(shí),你會(huì)在狀態(tài)管理庫 Mobx 或 Redux 的選擇上猶豫。應(yīng)該選哪個(gè)呢?由于 Mobx 是無主張的,使用上可以和 setState() 類似,我建議在小項(xiàng)目中嘗試。一旦應(yīng)用開始變得越來越大,越來越多的人開發(fā)時(shí),你應(yīng)該考慮在 Mobx 上實(shí)行更多的限制條件或嘗試使用 Redux 。我使用兩個(gè)庫都很享受。即使你最后兩個(gè)都沒使用,了解到狀態(tài)管理的另一種方式也是有意義的。

嘗試另一個(gè)狀態(tài)管理方案?

你可能已經(jīng)使用了其中一個(gè)狀態(tài)管理方案,但是想考慮另一個(gè)?你可以比較現(xiàn)實(shí)中的 Mobx 和 Redux 應(yīng)用。我把所有的文件修改都提交到了一個(gè)Pull Request 。在這個(gè) PR 里,項(xiàng)目從 Redux 重構(gòu)成了 Mobx ,反之亦然,你可以自己實(shí)現(xiàn)。我不認(rèn)為有必要和 Redux 或 Mobx 耦合,因?yàn)榇蟛糠值母淖兪呛推渌魏螙|西解耦的。

你主要需要將 Redux 的 Actions、Action Creator、 Action Types、Reducer、Global Store 替換成 Mobx 的 Stores 。另外將和 React 組件連接的接口 react-redux 換成 mobx-react 。presenter + container pattern 依然可以執(zhí)行。你僅僅還要重構(gòu)容器組件。在 Mobx 中可以使用 inject 獲得 store 依賴。然后 store 可以傳遞 substate 和 actions 給組件。Mobx 的 observer 確保組件在 store 中 observable 的屬性變化時(shí)更新。

import { observer, inject } from 'mobx-react';
...
const UserProfileContainer = inject(
 'userStore'
)(observer(({
 id,
 userStore,
}) => {
 return (
 <UserProfile
 user={userStore.getUser(id)}
 onUpdateUser={userStore.updateUser}
 />
 );
}));

Redux 的話,你使用 mapStateToProps 和 mapDispatchToProps 傳遞 substate 和 actions 給組件。

import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
...
function mapStateToProps(state, props) {
 const { id } = props;
 const user = state.users[id];
 return {
 user,
 };
}
function mapDispatchToProps(dispatch) {
 return {
 onUpdateUser: bindActionCreators(actions.updateUser, dispatch),
 };
}
const UserProfileContainer = connect(mapStateToProps, mapDispatchToProps)(UserProfile);

這有一篇怎樣將 Redux 重構(gòu)為 Mobx指南。但就像我上面說過的,反過來一樣也是可以的。一旦你選擇了一個(gè)狀態(tài)管理庫,你會(huì)知道那并沒有什么限制。它們基本上是和你的應(yīng)用解耦的,所以是可以替換的。

最后思考

每當(dāng)我看 Redux vs Mobx 爭論下的評論時(shí),總會(huì)有下面這條:“Redux 有太多的樣板代碼,你應(yīng)該使用 Mobx,可以減少 xxx 行代碼”。這條評論也許是對的,但沒人考慮得失,Redux 比 Mobx 更多的樣板代碼,是因?yàn)樘囟ǖ脑O(shè)計(jì)約束。它允許你推斷應(yīng)用狀態(tài)即使應(yīng)用規(guī)模很大。所以圍繞 state 的儀式都是有原因的。

Redux 庫非常小,大部分時(shí)間你都是在處理純 JavaScript 對象和數(shù)組。它比 Mobx 更接近 vanilla JavaScript 。Mobx 通過包裝對象和數(shù)組為可觀察對象,從而隱藏了大部分的樣板代碼。它是建立在隱藏抽象之上的。感覺像是出現(xiàn)了魔法,但卻很難理解其內(nèi)在的機(jī)制。Redux 則可以簡單通過純 JavaScript 來推斷。它使你的應(yīng)用更簡單的測試和調(diào)試。
另外,我們重新回到單頁應(yīng)用的最開始來考慮,一系列的單頁應(yīng)用框架和庫面臨著相同的狀態(tài)管理問題,它最終被 flux 模式解決了。Redux 是這個(gè)模式的成功者。

Mobx 則又處在相反的方向。我們直接修改 state 而沒有擁抱函數(shù)式編程的好處。對一些開發(fā)者來說,這讓他們覺得像雙向綁定。一段時(shí)間之后,由于沒有引入類似 Redux 的狀態(tài)管理庫,他們可能又會(huì)陷入同樣的問題。狀態(tài)管理分散在各個(gè)組件,導(dǎo)致最后一團(tuán)糟。

使用 Redux,你有一個(gè)既定的模式組織代碼,而 Mobx 則無主張。但擁抱 Mobx 最佳實(shí)踐會(huì)是明智的。 開發(fā)者需要知道如何組織狀態(tài)管理從而更好的推斷它。不然他們就會(huì)想要直接在組件中修改它。

兩個(gè)庫都非常棒。Redux 已經(jīng)非常完善,Mobx 則逐漸成為一個(gè)有效的替代。

總結(jié)

以上就是本文關(guān)于在Redux 和 Mobx之間如何選擇的問題,相信大家閱讀過本文之后應(yīng)該有了清晰的了解。

謝謝大家對本站的支持!

新聞標(biāo)題:Redux和Mobx的選擇問題:讓你不再困惑!
網(wǎng)址分享:http://bm7419.com/article32/igogsc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站內(nèi)鏈、靜態(tài)網(wǎng)站、網(wǎng)站制作、域名注冊、網(wǎng)站策劃、面包屑導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

商城網(wǎng)站建設(shè)