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(        ,  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-PWAserviceWorker.unregister();

可能你已经注意到了代码中的这一部分,似乎HTML中并没有这一标签,并且为什么JS文件中有这样类似HTML的东西呢?可能你的心中已经布满了疑问,没关系,让我们先动手改一下这段代码:

...    
hello world
  ,...

我想,上述写法应该能让你看出应该在哪里修改代码。现在,打开浏览器,看看localhost:3000这个页面,应该能看到页面发生了改变并显示了hello world。如果你之前不小心关闭了终端,请记得重新打开,并在frontend目录下运行yarn start。

这里我不打算详细介绍React的基础知识了,目前我还没有见过比React官方文档更好的学习资料,哪怕你觉得自己的英语很差劲,官方的中文文档也值得一看,这里我仅仅粗略介绍一下接下来要接触的知识点。

  • JSX:不够恰当但简单理解的话,可以认为在React中可以把HTML、CSS、JavaScript混合在一起,一个原本在HTML中的元素可以被赋值给变量,如const element = Hello, world!;,JSX里面也可以插入JS,如
const name = 'Josh Perez';// 使用JS变量const element = 

Hello, {name}

;
  • 组件:可以简单理解为,React认为UI应该是组件化的,就像搭积木一样,由一个一个组件搭起来,这样将一个大页面的工作拆分为很多个小组件,便于复用,也方便多人协作开发。之前看到的就是一个组件。
  • 生命周期函数:有一个有趣的比喻,把组件比作一只蚂蚁,它的一生就是从一根绳子的一端爬向另一端,这个绳子上挂了很多卡片,那么它从头爬到尾,就会在过程中触碰到不同的卡片,这些卡片就是生命周期函数

第一个组件

在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 
第一个组件
;  }}

render函数是类组件中唯一一个必须被实现的函数,组件将根据这个函数的返回值渲染内容。这里的

第一个组件
就是JSX,如果有多行嵌套可以用括号括起来:
return (      
        
文章一
        
文章二
      
    );

那怎么让这个组件被渲染呢?聪明的你可能已经把App.js的代码看了一遍,我们在ArticleList.js的最后面添加一行代码

export default ArticleList;

同时修改index.js:

import React from 'react';......// 原先引入App的那行可以删掉import ArticleList from './ArticleList'ReactDOM.render(        ,  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 (      
        {this.state.articleList.map(item =>          
            
{item.title}
            

              {item.body}              创建时间:{item.created}              更新时间:{item.updated}            

          
        )}      
    );  }

现在来大致讲解一下上面的代码,首先我们看到最外层的div标签,它拥有一个className属性,这个实际上就是HTML的class属性,这么写的原因也很简单,JSX允许JS和HTML混合在一起,但在很多编程语言(包括JS)里class都是用于创建类的关键字,所以给它改个名字便于区分。

接着我们看到了在JSX中如何使用JavaScript,我们在大括号里使用了map方法,使用箭头函数,让不同标签里包含了文章标题、正文等内容。

注意到包含

这一行,现在如果你已经使用了yarn start命令,你将会在浏览器看到一个简陋的文章列表,如果你删除这个key={item.id},在浏览器按下F12,你将会在控制台看到警告信息。
69fd75e5ea71afdbdf7e8ec8f4d011cf.png

FBI Warning

总之记住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,你会看到如下报错:

6fd7f7d272220564d14326fd27d54ea5.png

报错

虽然域名(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,可以在浏览器看到你在后端添加的数据啦。

2870ef56c9f2ddc7a7c6618323449d80.png

效果图

结语

这次就讲到这里了,下一章要讲讲将这次的代码在细节上优化一下。这一章有很多React的基础知识并没有讲解,如果读者对React目前还没有一点了解,那么建议现在去React官网看一下,至少把基础教程看完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值