今日藏书组件

本页面已浏览95次

今日藏书组件

这一章中我们要实现“今日藏书组件”,列出在历史上的今天我们收藏了哪些书。由于历史上的今天收藏的书可能有好几本,所以在本章中我们要学到如何对返回的记录集进行遍历。

获取数据的方式很常规,我们在componentDidMount中进行远程API的访问:

class Today extends Component {
  state={today: ''};

  componentDidMount() {
    fetch('http://api.rsywx.com/book/ofDay')
      .then(response => {
        return response.json();
      })
      .then(json => {
        this.setState({
          today: json.out,
        });
      })
  };
...

值得注意的一个地方是,我们在这个类的实现中,对我们要用到的state变量进行了初始化,使它有一个成员today,并初始为一个空字符串。

为什么要那么做,我们马上就会看到。

render函数中的循环

首先列出函数完整代码。

render() {
    let today=this.state.today;
    return (

      <div className="widewrapper">
        <div className="container content">
            <div className="row">
                <div className="col-sm-12">
                    <div className="showroom-controls">
                        <div className="links">历史上的收藏</div>
                    </div>
                    <div className="row cropping">
                      <div className="showroom-item blog-item col-sm-12">
                        <p>历史上的{String(new Date().getMonth()+1).padStart(2, '0')}月{String(new Date().getDate()).padStart(2, '0')}日,任氏有无轩主人购买和/或登录了{this.state.today.length}本书。它们是:</p>
                        <div>
                          {

                            Object.keys(today).map(function (key) {
                              var item=today[key];
                              return (
                                <span key={item.bookid}>
                                  <a href={"/books/"+item.bookid+".html"}>{item.title}</a>({item.fromnow}年前)&nbsp;&nbsp;
                                </span>
                              );
                            })
                          }
                        </div>
                      </div>
                    </div>
                    <div className="clearfix"></div>
                </div>
            </div>
        </div>
    </div>
    );
  }

我们做了几件事情。

  • 首先,为了方便后续的操作,我们设置了一个局部变量today
  • 其次,我们用了map这个函数对返回的JSON数据集进行循环。

我们调用的API会返回这样的一串东西:

{
    "status":200,
    "out":[
        {
            "id":"1751",
            "place":"2",
            "publisher":"2",
            "bookid":"01751",
            "title":"\u6ca1\u6709\u65f6\u95f4\u7684\u4e16\u754c",
            "author":"\u5c24\u683c\u62c9",
            "region":"\u7f8e\u56fd",
            "copyrighter":"\u5c24\u65af\u5fb7",
            "translated":"1",
        }
    ]
}

today变量会包含JSON中的out部分,而且会包含若干本(0到N本)书籍的信息。

我们会在一个div中显示所有在历史上的今日购买的书籍。所以,我们在这个div中进行循环。

这个循环的实现比PHP要复杂一些,也不那么直观。

首先我们要将这个today变量转变为可遍历的一个对象,而这是通过Object.keys(today)完成的。如此操作后,我们再用.map对该对象进行遍历,每次遍历都返回一个“基本”类似的HTML节点:

var item=today[key];
return (
  <span key={item.bookid}>
    <a href={"/books/"+item.bookid+".html"}>{item.title}</a>({item.fromnow}年前)&nbsp;&nbsp;
  </span>
);

首先,我们获得当前要操作的项目(item)。注意,我们这里是直接通过today[key]来获取,然后再通过item.bookid这样的形式来访问该对象的成员。

其次,因为我们在这个map函数中,对today变量也进行了操作(var item=today[key]),所以我们需要在该组件类的声明中,先对state变量进行一些初始化,让它先有一个today成员。

我们在异步获取today数据的同时,render函数已经开始渲染HTML的DOM树,所以它也会开始进行所有的对state中的变量(以及变量如果为对象,那么对该变量的成员)的访问。如果我们没有事先声明一个today的状态变量,那么这个变量只能由componentDidMount来完成。render在该状态变量创建之前对该变量的成员进行访问,只会让React无所适从,直接抛出错误了事。页面也就得不到渲染。1

第三,请注意每个生成的<span>节点。我们人为地为其加上了key这个属性。这是React的强制要求。这是因为,React需要这个参数来“分辨”(identify)这些批次性循环生成的节点以便插入最后的DOM树。我们在这里用“bookid”作为每个节点(也就是每本书)的key值。

注意:Firefox內置的调试器是非常非常非常好用的工具。请读者一定要仔细研究、熟练使用。而且它还可以挂载一个React专用的DOM节点搜索工具。大家应该记得,在React中,所有的DOM节点都是动态生成的。有这么一个工具的话,我们在DOM树中搜索节点会方便很多:


  1. 这个情况在不借助中间变量而直接对state变量操作时一样会出现。 

Previous Post Next Post