jsonp react 获取返回值_Django+React全栈开发:文章列表
React
現在我們有了一個屬于文章的API,可以添加、修改、刪除、查看文章,但是對于我們的網站來說,還需要一個用戶界面才行。現在開始探索一下ReactJS吧。
經常聽到有前端三大框架Angular、React、Vue的說法,不過React官網對自己的介紹卻是這樣的:
A JavaScript library for building user interfaces一個用來構建用戶界面的JavaScript庫。首先我們需要配置一下環境,以便使用React。
首先我們要安裝一個Node.js,目前我們還不用深入了解Node,只需要知道它能幫助你在非瀏覽器環境下運行JS代碼就行了。官網為node.org,直接下載安裝就行,Linux用戶推薦用各自的包管理器安裝。
Node自帶包管理器npm,有點類似Python的pip,不過這里我們使用yarn這個包管理器。按照官網說明安裝完之后,打開終端,并進入我們的項目目錄react_drf,為接下來的工作做準備。
從零開始構建一個React項目涉及到的東西是比較多的,這時候就有一些方便的腳手架可以選擇,腳手架可以幫我們省掉很多麻煩的配置。在這里先選用Facebook官方提供的create-react-app。
$ yarn create react-app frontend使用上述命令后,你將會看到react_drf目錄下多了個frontend文件夾:
$ cd frontend $ yarn start這下你會看到瀏覽器跳轉到localhost:3000,并且應該看到一個轉動的React logo的頁面,這說明你安裝成功了,接下來瀏覽一下frontend這個目錄下的文件,但還不要做任何改動。
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中可以把HTML、CSS、JavaScript混合在一起,一個原本在HTML中的元素可以被賦值給變量,如const element = <h1>Hello, world!</h1>;,JSX里面也可以插入JS,如
- 組件:可以簡單理解為,React認為UI應該是組件化的,就像搭積木一樣,由一個一個組件搭起來,這樣將一個大頁面的工作拆分為很多個小組件,便于復用,也方便多人協作開發。之前看到的<App />就是一個組件。
- 生命周期函數:有一個有趣的比喻,把組件比作一只螞蟻,它的一生就是從一根繩子的一端爬向另一端,這個繩子上掛了很多卡片,那么它從頭爬到尾,就會在過程中觸碰到不同的卡片,這些卡片就是生命周期函數。
第一個組件
在frontend/src目錄下創建新文件ArticleList.js,正如名字所示,這是一個文章列表的組件。
import React, {Component} from "react";class ArticleList extends Component {constructor(props) {super(props);}}現在我們定義了一個類組件,它繼承自React的Component類,這里我們寫了它的第一個生命周期函數,也就是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屬性,這個實際上就是HTML的class屬性,這么寫的原因也很簡單,JSX允許JS和HTML混合在一起,但在很多編程語言(包括JS)里class都是用于創建類的關鍵字,所以給它改個名字便于區分。
接著我們看到了在JSX中如何使用JavaScript,我們在大括號里使用了map方法,使用箭頭函數,讓不同標簽里包含了文章標題、正文等內容。
注意到包含<div key={item.id}>這一行,現在如果你已經使用了yarn start命令,你將會在瀏覽器看到一個簡陋的文章列表,如果你刪除這個key={item.id},在瀏覽器按下F12,你將會在控制臺看到警告信息。
總之記住React要求這類列表元素,必須要要有一個唯一的key標識來讓React能識別哪些元素被改變了。在后臺的真實數據中,id這個字段是主鍵,也就是唯一的,剛好可以利用。
使用API
好了,我們已經使用虛假的數據嘗試了一把,之前說過前后端分離開發的一個好處是前端與后端約定好接口后,可以各自分開并行開發,那么實質上就會有一些工具來幫助生成“假的API”或者虛假的前端請求之類來幫助測試,有興趣的可以去搜索搜索。
當然這里我們是為了學習,開發只有自己一個人而已,那現在讓我們來試試使用真實的API吧。
同源策略
在正式開始之前,我們還要先了解一下瀏覽器的同源策略。想象一下,如果你在a.com登錄瀏覽了一段時間,再跑去b.com逛逛,結果b.com直接取到了你在a.com的cookie,用于在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后臺在8000,React卻在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官網看一下,至少把基礎教程看完。
歡迎關注我的公眾號“公子政的宅日常”,原創技術文章第一時間推送。
D
總結
以上是生活随笔為你收集整理的jsonp react 获取返回值_Django+React全栈开发:文章列表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql 备份_MySQL数据库备份实
- 下一篇: 判断resultset是否遍历到最后一条