React + Node 單頁應用「一」前端搭建


項目地址
預覽地址
原文地址

記錄最近做的一個 demo,前端使用 React,用 React Router 實現前端路由,Koa 2 搭建 API Server, 最后通過 Nginx 做請求轉發。

這是第一篇,主要介紹下前端代碼的構建、React router 使用中遇到問題,以及前端開發完成后部署相關工作。

功能介紹

GitCard 可以通過 GitHub 授權獲取用戶基本信息

  • 在首頁模塊,可以查看最近登錄的用戶,並點擊頭像查看該用戶的詳細信息
  • /Comment 模塊中可以發表評論,並刪除自己的評論
  • /Detail 模塊中可以查看用戶在 Github 上的基本信息(代碼庫,Follower、Following 以及更多開發的信息),你可以在這個基礎上做更多有意思的事情,支持 Follow 和 Unfollow 操作,當然,你可以加上 Star 和 Unstar 操作,異曲同工。🈳️

依賴版本

  • 構建工具: create-react-app
  • react: 16.0.0
  • react-router: 4.2.2
  • 網絡請求: axios
  • UI: material-ui

項目搭建

前端構建工具使用 React 官方的 create-react-app,快速生成可執行的項目結構。下面是快速上手流程,詳細的內容可以參見 官方文檔

// 全局安裝 create-react-app
npm install -g create-react-app

//生成項目,項目名 my-app(自定義)
create-react-app my-app
cd my-app

// 安裝依賴
npm install
// 開發環境
npm start
// 打包
npm run build

生成項目后,項目文件結構如下,npm run build 執行后,目錄下會出現 /build/ 目錄,存放構建后的文件。

/**
 * my-app 目錄結構
 */
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public 
│   └── favicon.ico
│   └── index.html
│   └── manifest.json
└── src
    └── App.css
    └── App.js //項目入口
    └── App.test.js
    └── index.css
    └── index.js
    └── logo.svg
    └── registerServiceWorker.js

我們在 /src/ 目錄下新建 /components/ 目錄,用於存放本次項目中的所有自定義組件,最終的目錄如下

.
├── README.md
├── build
├── package.json
├── public
├── src
│   ├── App.css
│   ├── App.js
│   ├── App.test.js
│   ├── components
│   │   ├── Comments
│   │   │   ├── comment.css
│   │   │   └── index.jsx
│   │   ├── Events
│   │   │   └── index.jsx
│   │   ├── HomePage
│   │   │   └── index.jsx
│   │   ├── UserDetail
│   │   │   └── index.jsx
│   │   └── layouts
│   │       ├── Header.jsx
│   │       └── SideMenu.jsx
│   ├── index.css
│   ├── index.js
│   ├── logo.svg
│   ├── registerServiceWorker.js
│   └── utils
│       ├── api.jsx
│       ├── fetch.jsx
│       └── keygen.js
└── yarn.lock

前端路由

這次做的項目是單頁應用,通過 React router 實現前端路由,Container 通過路由選擇顯示的模塊內容,在 Header 顯示路由切換入口,頁面結構圖如下。

/src/App.js 布局並設置路由,將 HeaderContainer 包在 Router 下,在 Header 的 Menu 組件中設置路由鏈接,並在 Container 中設置路由指向對應組件。

Menu 中 Detail 鏈接在用戶授權登錄后就指向登錄用戶信息,否則跳轉到授權登錄頁面。

// 引入 React router
import {
  BrowserRouter as Router,
  Link,
  Route
} from "react-router-dom"

// 在 layout-content 中設置路由對應的組件
<Router>
    <div className="App">
        <Header loginInfo={this.state.loginInfo}></Header>
        <div className="layout-container">
            <div className="layout-content">
                <Route exact path="/" component={ HomePage } ></Route>
                <Route path="/user/:userid" component={ UserDetail } ></Route>
                <Route path="/events" component={Events}></Route>
                <Route path="/comments" render={ ()=><Comments loginInfo={this.state.loginInfo} /> }></Route>
            </div>
        </div>
    </div>
</Router>

// 在 Header 中設置 Link 
<Menu>
    <Link to="/">
        <MenuItem primaryText="Home" />
    </Link>
    <Link to="/comments">
        <MenuItem primaryText="Comments"/>
    </Link>
    {
    this.props.loginInfo.login ?
      (<Link to={  '/user/' + this.props.loginInfo.login }>
            <MenuItem primaryText="Detail" />
      </Link>)
      : (<MenuItem primaryText="Login" onClick={this.login} />)
    }
</Menu>

數據操作

路由下發數據

上面的代碼的路由中,我們通過兩種方式下發數據到組件中,通過路由參數將用戶 ID 下發到 Detail 組件,以及通過 props 講用戶基本信息下發到 Comment 組件中。

// 通過路由參數下發的 Link 以及對應的 Route
<Link to={  '/user/' + this.props.loginInfo.login }><MenuItem primaryText="Detail" /></Link>
<Route path="/user/:userid" component={ UserDetail } ></Route>

// 通過 props 下發
<Route path="/comments" render={ ()=><Comments loginInfo={this.state.loginInfo} /> }></Route>

通過路由參數獲取下發數據,如果在 /user/lijundong 跳轉到 /user/free-free 會出現路由改變,數據不刷新的情況,這里需要用 componentWillReceiveProps(nextProps) 處理。

Detail 組件中獲取 ID,

const userId = this.props.match.params.userid;

以及在 Comment 中獲取用戶信息

const loginInfo = this.props.loginInfo;

數據請求

我們在這里選擇用 axios 網絡請求,為了方便管理,將所有的 API 統一放在 /src/utils/api.jsx 中,利於后期維護。
沒有使用 Fetch 是因為 Github API 只支持 XHR 跨域請求,Fetch 跨域請求會導致請求 request type 變成 option

數據更新

setState

因為這次的數據並不復雜,所以沒有引入 MobX 或者 Redux 處理,數據更新全程使用 setState,不過由於 setState 是異步操作,所以,某些情況下,需要用到回調函數,如下

setState(
  { name: "Michael" },
  () => console.log(this.state.name)
);
// Michael

componentWillReceiveProps

上面提到過,通過路由參數獲取下發數據,如果在 /user/lijundong 跳轉到 /user/free-free 會出現路由改變,數據不刷新的情況,這是因為 componentDidMount() 只會執行一次,props 更新不會觸發重新獲取數據,這里可通過 componentWillReceiveProps() 解決。

componentWillReceiveProps() 會在每次 props 更新時觸發,通過新參數重新獲取數據列表。

componentWillReceiveProps(nextProps){
    const userId = nextProps.match.params.userid;
// 通過新參數獲取數據
    Axios.get(url)
}

項目構建部署

項目開發結束,通過 npm run build 進行打包,打包完成后,生成的 /build/ 即我們最終上線的版本,因為是前后端分離的項目,前端需要自起 Server,可以通過這兩種方案進行部署

  • 使用 create-react-app 自帶的 serve -s build 命令起 Server(我當前使用的方式)
  • 或者通過第三方工具 http-serveranywhere 等起 Server

服務開啟后,可以正常訪問就代表前端部分已經完成,暴露的端口供最后 Nginx 配置使用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM