Django+React全棧開發:文章列表

React

如今咱們有了一個屬於文章的API,能夠添加、修改、刪除、查看文章,可是對於咱們的網站來講,還須要一個用戶界面才行。如今開始探索一下ReactJS吧。css

常常聽到有前端三大框架Angular、React、Vue的說法,不過React官網對本身的介紹倒是這樣的:html

A JavaScript library for building user interfaces

一個用來構建用戶界面的JavaScript庫。首先咱們須要配置一下環境,以便使用React前端

首先咱們要安裝一個Node.js,目前咱們還不用深刻了解Node,只須要知道它能幫助你在非瀏覽器環境下運行JS代碼就好了。官網爲node.org,直接下載安裝就行,Linux用戶推薦用各自的包管理器安裝。node

Node自帶包管理器npm,有點相似Python的pip,不過這裏咱們使用yarn這個包管理器。按照官網說明安裝完以後,打開終端,並進入咱們的項目目錄react_drf,爲接下來的工做作準備。react

從零開始構建一個React項目涉及到的東西是比較多的,這時候就有一些方便的腳手架能夠選擇,腳手架能夠幫咱們省掉不少麻煩的配置。在這裏先選用Facebook官方提供的create-react-appnpm

$ yarn create react-app frontend

使用上述命令後,你將會看到react_drf目錄下多了個frontend文件夾:編程

$ cd frontend
$ yarn start

這下你會看到瀏覽器跳轉到localhost:3000,而且應該看到一個轉動的React logo的頁面,這說明你安裝成功了,接下來瀏覽一下frontend這個目錄下的文件,但還不要作任何改動。json

index.js

如今讓咱們一塊兒來看一下frontend/src這個目錄,基本上目前咱們只要關心這個目錄下的內容就能夠了。首先來看一下這裏的frontend/src/index.js後端

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

可能你已經注意到了代碼中的<App />這一部分,彷佛HTML中並無這一標籤,而且爲何JS文件中有這樣相似HTML的東西呢?可能你的心中已經佈滿了疑問,不要緊,讓咱們先動手改一下這段代碼:瀏覽器

...
<React.StrictMode>
    <div>hello world</div>
  </React.StrictMode>,
...

我想,上述寫法應該能讓你看出應該在哪裏修改代碼。如今,打開瀏覽器,看看localhost:3000這個頁面,應該能看到頁面發生了改變並顯示了hello world。若是你以前不當心關閉了終端,請記得從新打開,並在frontend目錄下運行yarn start

這裏我不打算詳細介紹React的基礎知識了,目前我尚未見過比React官方文檔更好的學習資料,哪怕你以爲本身的英語不好勁,官方的中文文檔也值得一看,這裏我僅僅粗略介紹一下接下來要接觸的知識點。

  • JSX:不夠恰當但簡單理解的話,能夠認爲在React中能夠把HTMLCSSJavaScript混合在一塊兒,一個本來在HTML中的元素能夠被賦值給變量,如const element = <h1>Hello, world!</h1>;JSX裏面也能夠插入JS,如
const name = 'Josh Perez';
// 使用JS變量
const element = <h1>Hello, {name}</h1>;
  • 組件:能夠簡單理解爲,React認爲UI應該是組件化的,就像搭積木同樣,由一個一個組件搭起來,這樣將一個大頁面的工做拆分爲不少個小組件,便於複用,也方便多人協做開發。以前看到的<App />就是一個組件。
  • 生命週期函數:有一個有趣的比喻,把組件比做一隻螞蟻,它的一輩子就是從一根繩子的一端爬向另外一端,這個繩子上掛了不少卡片,那麼它從頭爬到尾,就會在過程當中觸碰到不一樣的卡片,這些卡片就是生命週期函數

第一個組件

frontend/src目錄下建立新文件ArticleList.js,正如名字所示,這是一個文章列表的組件。

import React, {Component} from "react";

class ArticleList extends Component {
  constructor(props) {
    super(props);
  }

}

如今咱們定義了一個類組件,它繼承自ReactComponent類,這裏咱們寫了它的第一個生命週期函數,也就是constructor,若是你熟悉過任何一門面向對象的語言,這裏應該不難理解。constructor並非React獨有的,而是JavaScript原生的寫法,不過對於類組件來講,它固然也能夠算生命週期的一部分。

如今來看第二個生命週期函數render

class ArticleList extends Component {
  constructor(props) {
    ......
  }

  render() {
    return <div>第一個組件</div>;
  }

}

render函數是類組件中惟一一個必須被實現的函數,組件將根據這個函數的返回值渲染內容。這裏的<div>第一個組件</div>就是JSX,若是有多行嵌套能夠用括號括起來:

return (
      <div className="ArticleList">
        <div>文章一</div>
        <div>文章二</div>
      </div>
    );

那怎麼讓這個組件被渲染呢?聰明的你可能已經把App.js的代碼看了一遍,咱們在ArticleList.js的最後面添加一行代碼

export default ArticleList;

同時修改index.js

import React from 'react';
......
// 原先引入App的那行能夠刪掉
import ArticleList from './ArticleList'

ReactDOM.render(
  <React.StrictMode>
    <ArticleList />
  </React.StrictMode>,
  document.getElementById('root')
);

......

如今運行yarn start,你將在看到瀏覽器啓動並顯示你在render函數中返回的內容。固然事實上若是你以前沒有中止終端的運行,那麼就沒必要要從新運行yarn start,代碼作了更改,會自動從新渲染,之後再也不提醒如何查看咱們的成果了。

接下來開始實現文章列表界面,可是先不急着從API獲取文章數據,先讓咱們模擬一下文章數據:

const articleList = [
  {
    "id": 2,
    "title": "React",
    "body": "React is good",
    "created": "2020-03-21T21:19:31.732703",
    "updated": "2020-03-21T21:19:31.732728"
  },
  {
    "id": 1,
    "title": "React",
    "body": "React is good",
    "created": "2020-03-21T21:10:53.922033",
    "updated": "2020-03-21T21:10:53.922128"
  }
];

class ArticleList extends Component {
  constructor(props) {
    super(props);
    this.state = {
      articleList: articleList,
    }
  }
  ......
}

注意到這裏添加了一個articleList列表,在構造函數裏多了一個this.state,併爲其設置了articleList屬性。如今來修改render函數:

render() {
    return (
      <div className="ArticleList">
        {this.state.articleList.map(item =>
          <div key={item.id}>
            <h4>{item.title}</h4>
            <p>
              <strong>{item.body}</strong>
              <br/>
              <em>建立時間:{item.created}</em>
              <em>更新時間:{item.updated}</em>
            </p>
          </div>
        )}
      </div>
    );
  }

如今來大體講解一下上面的代碼,首先咱們看到最外層的div標籤,它擁有一個className屬性,這個實際上就是HTMLclass屬性,這麼寫的緣由也很簡單,JSX容許JSHTML混合在一塊兒,但在不少編程語言(包括JS)裏class都是用於建立類的關鍵字,因此給它改個名字便於區分。

接着咱們看到了在JSX中如何使用JavaScript,咱們在大括號裏使用了map方法,使用箭頭函數,讓不一樣標籤裏包含了文章標題、正文等內容。

注意到包含<div key={item.id}>這一行,如今若是你已經使用了yarn start命令,你將會在瀏覽器看到一個簡陋的文章列表,若是你刪除這個key={item.id},在瀏覽器按下F12,你將會在控制檯看到警告信息。

FBI Warning

總之記住React要求這類列表元素,必需要要有一個惟一的key標識來讓React識別哪些元素被改變了。在後臺的真實數據中,id這個字段是主鍵,也就是惟一的,恰好能夠利用。

使用API

好了,咱們已經使用虛假的數據嘗試了一把,以前說過先後端分離開發的一個好處是前端與後端約定好接口後,能夠各自分開並行開發,那麼實質上就會有一些工具來幫助生成「假的API」或者虛假的前端請求之類來幫助測試,有興趣的能夠去搜索搜索。

固然這裏咱們是爲了學習,開發只有本身一我的而已,那如今讓咱們來試試使用真實的API吧。

同源策略

在正式開始以前,咱們還要先了解一下瀏覽器的同源策略。想象一下,若是你在a.com登陸瀏覽了一段時間,再跑去b.com逛逛,結果b.com直接取到了你在a.comcookie,用於在a.com登陸你的帳號,那實在是太可怕了,尤爲是當a.com是銀行或購物網站的時候。基於此,瀏覽器使用同源策略來作一個基本的安全保障。簡單來講,就是域名、端口、協議只要有一個不同,就會受到訪問限制:

  • Cookie、LocalStorage 和 IndexDB 沒法讀取。
  • DOM 沒法得到。
  • AJAX 請求不能發送。

咱們能夠簡單嘗試一下,修改ArticleList.js

constructor(props) {
    ......
  }

  componentDidMount() {
    fetch('http://127.0.0.1:8000/articles/')
      .then(response => response.json())
      .then(result => this.setState({articleList: result}))
      .catch(e => e);
  }
  ......

這裏咱們又見到了一個新的生命週期函數componentDidMount將在render以後執行。這裏調用了原生的fetch函數,直接簡單粗暴的請求API,在瀏覽器中按下F12,你會看到以下報錯:

報錯

雖然域名(IP)、協議都相同,可是端口號卻不一樣Django後臺在8000React卻在3000,因此發生了錯誤。

這裏給出一個在開發時能夠用的方案,幫助咱們解決這個問題,固然,在實際部署時不能這麼作,部署時的具體狀況之後再講,這裏咱們先找到frontend/package.json這個文件,在其中添加一行:

{
 .......,
 "proxy": "http://127.0.0.1:8000"
}

省略號表明以前的內容,若是你插入在文件最後面可別忘了給前面加一個逗號。

接着對源代碼作一處修改:

componentDidMount() {
    fetch('/articles/')
      ......
  }

這樣開發服務器就能識別你的請求將其代理到http://127.0.0.1:8000也就是Django服務所在的地址了,如今從新運行yarn start,能夠在瀏覽器看到你在後端添加的數據啦。

效果圖

結語

此次就講到這裏了,下一章要講講將此次的代碼在細節上優化一下。這一章有不少React的基礎知識並無講解,若是讀者對React目前尚未一點了解,那麼建議如今去React官網看一下,至少把基礎教程看完。


歡迎關注個人公衆號「公子政的宅平常」,原創技術文章第一時間推送。

myqr.gif

相關文章
相關標籤/搜索