翻譯 | 《JavaScript Everywhere》第12章 使用React構建Web客戶端javascript
你們好呀,我是毛小悠,是一位前端開發工程師。正在翻譯一本英文技術書籍。html
爲了提升你們的閱讀體驗,對語句的結構和內容略有調整。若是發現本文中有存在瑕疵的地方,或者你有任何意見或者建議,能夠在評論區留言,或者加個人微信:code_maomao,歡迎相互溝通交流學習。前端
(σ゚∀゚)σ..:*☆哎喲不錯哦java
超文本背後的原始想法是獲取相關文檔並將它們連接在一塊兒:若是學術論文A
引用學術論文B
,讓咱們能夠輕鬆地單擊某些內容並在它們之間導航。1989
年,CERN
的一位名爲Tim Berners-Lee
的軟件工程師提出了將超文本與聯網計算機相結合的想法,從而令人們能夠輕鬆地創建這些鏈接,而無論文檔的位置如何。每張貓的照片、新聞、推文、流媒體視頻、求職網站和餐廳評論都應歸功於全局連接文檔的簡單想法。react
從本質上講,網絡仍然是將文檔連接在一塊兒的媒介。在網絡瀏覽器中,每一個頁面都是HTML
,帶有CSS
(用於樣式設置)和JavaScript
(用於加強功能)。今天,咱們使用這些技術來構建從我的博客和小型手冊站點到複雜的交互式應用程序的全部內容。其根本優勢是Web
提供了通用訪問權限。任何人只須要一個能夠鏈接網絡的網絡瀏覽器,會建立一個默認的環境。git
在接下來的章節中,咱們將爲社交筆記應用Notedly
構建Web
客戶端。用戶將可以建立和登陸賬戶,在Markdown
中編寫筆記,編輯他們的筆記,查看其餘用戶筆記的摘要以及「收藏」其餘用戶筆記。爲此,咱們將與GraphQL
服務器API
進行交互。github
在咱們的Web
應用程序中:web
這些功能將涉及不少領域,可是在本書的這一部分中,咱們將把它們分紅小塊。一旦學會了使用全部這些功能構建React
應用程序,就能夠將工具和技術應用於構建各類富Web
應用程序。npm
你可能已經猜到了,要構建此應用程序,咱們將使用React
做爲客戶端JavaScript
庫。此外,咱們將從GraphQL API
查詢數據。爲了幫助查詢,修改和緩存數據,咱們將使用Apollo
客戶。Apollo Client
包含用於使用GraphQL
的一系列開源工具。咱們將使用庫的React
版本,可是Apollo
的團隊還開發了Angular
,Vue
,Scala.js
,Native iOS
和Native Android
集成。後端
儘管咱們將在本書中使用Apollo
,但它遠遠不是惟一一個GraphQL
客戶端選項。Facebook
的Relay
和Formiddable
的urql
也是兩個受歡迎的選擇。
此外,咱們將使用parcel
做爲咱們的代碼捆綁器。代碼捆綁器使咱們可使用Web
瀏覽器中可能不具有的功能(例如,較新的語言功能,代碼模塊,壓縮)編寫JavaScript
,並將其打包以供在瀏覽器環境中使用。Parcel
是Webpack
等應用程序構建工具的無配置替代方案。它提供了許多不錯的功能,例如代碼拆分和在開發過程當中自動更新瀏覽器(又稱熱模塊替換),而無需創建構建。如上一章所述,create-react-app
它還提供了零配置的初始設置,在後臺使用Webpack
,但Parcel
容許咱們從頭開始構建應用程序,這是我發現學習的理想方式。
在開始開發以前,咱們須要將項目啓動代碼文件複製到咱們的電腦上。
項目的源代碼包含咱們開發應用程序所需的全部腳本和對第三方庫的引用。要將代碼克隆到本地計算機,請打開終端,導航到保存項目的目錄,而後git clone
項目存儲庫。若是你已經遍歷了API
章節,則可能已經建立了一個notedly目錄來保持項目代碼的條理性:
# change into the Projects directory $ cd $ cd Projects $ # type the `mkdir notedly` command if you don't yet have a notedly directory $ cd notedly $ git clone git@github.com:javascripteverywhere/web.git $ cd web $ npm install
經過使用本書的入門代碼的副本並在目錄中運行npm install
,你無需爲任何第三方依賴項再次運行npm install
。
該代碼的結構以下:
src
這是你隨書一塊兒進行開發的目錄。
solutions
該目錄包含每章的解決方案。若是你卡住了,這些能夠供你參考。
final
該目錄包含最終的工做項目。
如今,你已經在電腦上安裝了代碼,複製項目的.env
文件。這個文件保存了咱們特殊的工做環境變量。
例如,在本地工做時,咱們將指向API
的本地實例,可是在部署應用程序時,咱們將指向咱們遠程的API
。複製.env
文件,從Web
目錄在終端中鍵入如下內容:
$ cp .env.example .env
你如今應該看到一個.env
文件。你無需對該文件作任何事情,可是隨着API
後端的開發,咱們將向其中添加信息。項目附帶的.gitignore
文件將確保你不會無心間提交.env
文件。
默認狀況下,操做系統隱藏以句點開頭的文件,由於這些文件一般由系統使用,而不是最終用戶使用。若是看不到.env
文件,請嘗試在文本編輯器中打開目錄。該文件應該在編輯器的文件瀏覽器中可見。或者,在終端窗口中鍵入ls -a
將列出當前工做目錄中的文件。
在本地克隆了啓動代碼以後,咱們就能夠構建React Web
應用程序了。首先讓咱們看一下src/index.html
文件。這看起來像一個標準的但徹底爲空的HTML
文件,但請注意如下兩行:
<div id="root"></div> <script src="./App.js"></script>
這兩行對咱們的React
應用程序很是重要。
root
將提供整個應用程序的容器。同時,App.js
文件將成爲咱們JavaScript
應用程序的入口。
如今咱們能夠開始在src/App.js
文件中開發React
應用程序了。若是你跟隨上一章中的React
簡介,可能會以爲很熟悉。在src/App.js
中,咱們首先導入react
和react-dom
庫:
import React from 'react'; import ReactDOM from 'react-dom';
如今,咱們將建立一個名爲App
的函數,該函數將返回應用程序的內容。如今,這將只是元素中包含的兩行HTML
:
const App = () => { return ( <div> <h1>Hello Notedly!</h1> <p>Welcome to the Notedly application</p> </div> ); };
若是你只是從React
入手,你可能會想知道用標籤包圍組件的趨勢。React
的組件必須包含於父元素,這每每是一種標籤,但也能夠是任何其餘適當的HTML
標籤,例如,,或.
若是感受包含HTML
的標記多餘,咱們能夠用空的<>標記在咱們的JavaScript
代碼中包含這些組件。
最後,咱們將經過添加如下內容來指示React
在根ID
爲root
的元素內渲染應用程序:
ReactDOM.render(<App />, document.getElementById('root'));
如今,咱們的src/App.js
文件的完整內容應爲:
import React from 'react'; import ReactDOM from 'react-dom'; const App = () => { return ( <div> <h1>Hello Notedly!</h1> <p>Welcome to the Notedly application</p> </div> ); }; ReactDOM.render(<App />, document.getElementById('root'));
完成此操做後,讓咱們在Web
瀏覽器中進行查看。經過在終端應用程序中鍵入npm run dev
來啓動本地開發服務器。編譯代碼後,請訪問 http://localhost:1234
來查看頁面(圖12-1
)。
圖12-1
咱們最初在瀏覽器中運行的React
應用程序
網絡的定義特徵之一是可以將文檔連接在一塊兒。一樣,對於咱們的應用程序,咱們但願用戶可以在屏幕或頁面之間導航。在HTML
呈現的應用程序中,這將涉及建立多個HTML
文檔。每當用戶導航到新文檔時,即便兩個頁面上存在共享的方面(例如頁眉或頁腳),整個文檔也會從新加載。
在JavaScript
應用程序中,咱們能夠利用客戶端路由。在許多方面,這將相似於HTML
連接。用戶將單擊一個連接,URL
將更新,而且他們將導航到新屏幕。不一樣之處在於咱們的應用程序只會使用更改後的內容來更新頁面。體驗將是「相似於應用程序的」的流暢,這意味着將不會看到頁面的刷新。
在React
中,最經常使用的路由庫是Router
。這個庫使咱們可以向React Web
應用程序添加路由功能。爲了將路由引入咱們的應用程序,讓咱們首先建立一個src/pages
目錄並添加如下文件:
src/pages/index.js
src/pages/home.js
src/pages/mynotes.js
src/pages/favorites.js
咱們的home.js
,mynotes.js
和favorite.js
文件將成爲咱們單獨的頁面組件。咱們能夠爲每一個文件建立一些初始內容和效果鉤子,當用戶導航到頁面時,它們將更新文檔標題。
在src/pages/home.js
中:
import React from 'react'; const Home = () => { return ( <div> <h1>Notedly</h1> <p>This is the home page</p> </div> ); }; export default Home;
在src/pages/mynotes.js
中:
import React, { useEffect } from 'react'; const MyNotes = () => { useEffect(() => { // update the document title document.title = 'My Notes — Notedly'; }); return ( <div> <h1>Notedly</h1> <p>These are my notes</p> </div> ); }; export default MyNotes;
在src/pages/favorites.js
中:
import React, { useEffect } from 'react'; const Favorites = () => { useEffect(() => { // update the document title document.title = 'Favorites — Notedly'; }); return ( <div> <h1>Notedly</h1> <p>These are my favorites</p> </div> ); }; export default Favorites;
在前面的示例中,咱們使用React
的useEffect
鉤子來設置頁面標題。Effect
掛鉤使咱們在組件中存在反作用,會更新與組件自己無關的內容。若是你有興趣,能夠深刻探討React
的Effect hooks
文檔。
如今,在src/pages/index.js
中,咱們將使用react-router-dom
包導入React Router
和Web
瀏覽器路由所需的方法:
import React from 'react'; import { BrowserRouter as Router, Route } from 'react-router-dom';
接下來,咱們將導入剛剛建立的頁面組件:
import Home from './home'; import MyNotes from './mynotes'; import Favorites from './favorites';
最後,咱們將使用特定的URL
指定咱們建立爲路由的每一個頁面組件。請注意,對於咱們的「Home
」路由使用了徹底匹配,這將確保僅針對根URL
呈現主頁組件:
const Pages = () => { return ( <Router> <Route exact path="/" component={Home} /> <Route path="/mynotes" component={MyNotes} /> <Route path="/favorites" component={Favorites} /> </Router> ); }; export default Pages;
如今,咱們完整的src/pages/index.js
文件應以下所示:
// import React and routing dependencies import React from 'react'; import { BrowserRouter as Router, Route } from 'react-router-dom'; // import routes import Home from './home'; import MyNotes from './mynotes'; import Favorites from './favorites'; // define routes const Pages = () => { return ( <Router> <Route exact path="/" component={Home} /> <Route path="/mynotes" component={MyNotes} /> <Route path="/favorites" component={Favorites} /> </Router> ); }; export default Pages;
最後,咱們能夠經過導入路由並渲染組件來更新src/App.js
文件以使用咱們的路由:
import React from 'react'; import ReactDOM from 'react-dom'; // import routes import Pages from '/pages'; const App = () => { return ( <div> <Pages /> </div> ); }; ReactDOM.render(<App />, document.getElementById('root'));
如今,若是你在Web
瀏覽器中手動更新URL
,則應該可以查看每一個組件。例如,鍵入http:// localhost:1234/favorites
來呈現「收藏夾」頁面。
連接
咱們已經建立了頁面,可是缺乏將它們連接在一塊兒的關鍵部分。所以,讓咱們從首頁添加到其餘頁面的連接。爲此,咱們將使用React Router
的Link
組件。
在src/pages/home.js
中:
import React from 'react'; // import the Link component from react-router import { Link } from 'react-router-dom'; const Home = () => { return ( <div> <h1>Notedly</h1> <p>This is the home page</p> { /* add a list of links */ } <ul> <li> <Link to="/mynotes">My Notes</Link> </li> <li> <Link to="/favorites">Favorites</Link> </li> </ul> </div> ); }; export default Home;
這樣咱們就能夠瀏覽咱們的應用程序。
單擊主頁上的連接之一將導航到相應的頁面組件。
瀏覽器的核心導航功能(如後退和前進按鈕)也將繼續起做用。
咱們已經成功建立了單個頁面組件,而且能夠在它們之間進行導航。在構建頁面時,它們將具備幾個共享的用戶界面元素,例如標題和站點範圍的導航。每次使用它們時重寫它們都不會很是高效(而且會很煩人)。取而代之的是,咱們能夠編寫可重用的接口組件,並將它們導入到咱們須要的任何地方。實際上,將咱們的UI
視爲由微小的組件組成是React
的核心功能之一,也是我在掌握框架方面的突破。
咱們將從爲應用程序建立標題和導航組件開始。首先,讓咱們在src
目錄中建立一個名爲components
的新目錄。在src/components
目錄中,咱們將建立兩個名爲Header.js
和Navigation.js
的新文件。React
組件必須大寫,所以咱們也將遵循大寫文件名的慣例。
讓咱們首先在src/components/Header.js
中編寫標頭組件。爲此,咱們將導入logo.svg
文件,併爲咱們的組件添加相應的標記:
import React from 'react'; import logo from '../img/logo.svg'; const Header = () => { return ( <header> <img src={logo} alt="Notedly Logo" height="40" /> <h1>Notedly</h1> </header> ); }; export default Header;
對於咱們的導航組件,咱們將導入React Router
的Link
功能並標記一個無序的連接列表。在src/components/Navigation.js
中:
import React from 'react'; import { Link } from 'react-router-dom'; const Navigation = () => { return ( <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/mynotes">My Notes</Link> </li> <li> <Link to="/favorites">Favorites</Link> </li> </ul> </nav> ); }; export default Navigation;
在屏幕截圖中,你會發現我還包括了表情符號字符做爲導航圖標。
若是你要這樣作,包含表情符號字符的可訪問標記以下:
<span aria-hidden="true" role="img"> <!-- emoji character --> </span>
完成標題和導航組件後,咱們如今能夠在應用程序中使用它們了。讓咱們更新src/pages/home.js
文件以包含這些組件。咱們將首先導入它們,而後將組件包括在咱們的JSX
標記中。
咱們的src/pages/home.js
如今將以下所示(圖12-2
):
import React from 'react'; import Header from '../components/Header'; import Navigation from '../components/Navigation'; const Home = () => { return ( <div> <Header /> <Navigation /> <p>This is the home page</p> </div> ); }; export default Home;
圖12-2
使用React
組件,咱們能夠輕鬆地組合可共享的UI
功能。
這是咱們可以在咱們的應用程序中建立可共享組件所需的一切。有關在UI
中使用組件的更多信息,我強烈建議閱讀React
文檔頁「「Thinking in React」.
網絡仍然是分發應用程序的無比重要的媒介。它使開發者能夠實時更新訪問。
在本章中,咱們在React
中構建了JavaScript Web
應用程序。在下一章中,咱們將使用React
組件和CSS-in-JS
嚮應用程序添加布局和樣式。
若是有理解不到位的地方,歡迎你們糾錯。若是以爲還能夠,麻煩您點贊收藏或者分享一下,但願能夠幫到更多人。