上节课我们介绍了如何在List组件中来展示我们获取到的数据。到上节课我们其实就算是完成这儿个案例的所有功能了,但是我们有没有觉得页面不太合适啊?刚一打开的时候空荡荡的啥都没有。而且当我们点击搜索之后也没有任何提示,如果说搜索的速度很慢的话我们点击了搜索按钮一点提示都没有就很不合适。那么这节课我们就来把这些问题完善一下。

回顾

在完善上述问题之前,我们来对上节课的内容来做一个简单的回顾。

  • 平级组件共用的数据存放在公共父组件的state
  • 遍历一定要加上唯一性key

以上便是上节课的要点,没有什么新鲜的东西,都是以前旧知识的回顾,接下来我们来开始今天的内容。

页面展示

我们之前提到了我们打开页面的时候就空荡荡的一个页面,只有一个搜索模块,那么我们给价格欢迎词呗,虽然没有什么用但是显得不那么生硬。

那么我们来想一想展示部分是不是List组件?List组件中能展示什么?

  • users信息
  • 欢迎词
  • 搜索时的loading

那么就只有这么多吗?我们有没有想过如果axios发送请求出错了怎么办,我们是拿到了error,但是这个error我们在页面中展示吗?肯定要展示出错误信息的。不然的话我们页面也不出结果,也没有提示,那我们怎么办呢?

设置state

所以说List组件总共有 4 种不同的展示信息,不同的展示是不是要通过不同的state来驱动更新?那么我们来看一下啊App组件

export default class App extends Component {
  state = { 
    users: [],
    isFirst:true,
    isLoading:false,
    err:"" 
  };
 ...
}

首先我们要初始化我们的stateusers我们就不多说了,来看isFirst,这个是代表判断是不是第一次打开这个页面,我们默认是不是true?当我们用户点击按钮的时候再把这个属性设为false,这样的话一打开不就可以根据isFirst来加载欢迎词了嘛。

然后我们再来看isLoading,我们刚打开的时候肯定没有在加载啊,我们都是用户点了按钮,然后页面才会显示Loading,当拿到数据或者出错了再停止,所以说这个属性默认为false,等刚一发起请求改为true,请求完毕之后再重新改为false

最后看err属性,这个属性用来存储请求错误信息,当我们请求出现错误了,那么我们就可以通过这个属性来拿到错误原因展示在页面上。

入口函数

那么我们state中写了这么多属性,就只有一个saveUsers来作为入口函数是不是不够用啊?那么我们来定义相应的入口函数:

export default class App extends Component {
  state = {...};

  updateAppState = stateObj => this.setState(stateObj);

  render() {
    const { users } = this.state;
    return (
      <div className="container">
        <Search updateAppState={this.updateAppState} />
        <List users={users} />
      </div>
    )
  }
}

我们来看一下代码,我们把saveUsers给删了,用一个新的方法updateAppState来代替了。为什么?我们每个属性在被修改是不是都知识在修改state啊?那么我们直接让使用这些入口函数的人直接传一个state对象给入口函数不就醒了嘛,那么要写那么多呢。所以说这一个入口函数便可以完成我们所有的对state的操作。

使用入口函数

那么我们写好了入口函数了,我们就得用啊,我们来看看这么用,我们一但点击按钮,那么是不是要发起请求?这个时候我们的页面还是第一次打开的初始状态吗?这个时候已经是请求过程中的中间状态了。那么这个时候是不是要先把isFirst改掉?,而且当我们改掉之后是不是就再也不用改回来了?因为只要我们搜索了,在不重新打开页面的情况下这个页面是不是都已经不再是初始状态了?

那么好,我们把isFirst改掉之后,我们是不是要展示Loading?因为我们也不知道这个搜索过程要多久,如果不展示Loding的话用户体验实在太差了。所以说这个时候我们要把isLoading改为true,然后发送请求,这个请求就有两个分支了,第一个分支是请求成功了,我们要把数据给users属性,如果失败了,要把errorerr属性,那么在这之后我们还展示Loading吗?我们这个时候就要展示数据或者错误信息了啊。所以说我们要再次把isLoading改成false。那么好,我们来改一下代码:

export default class Search extends Component {
  render() {...}
  search = () => {
    const { value: keyword } = this.user;
    const {updateAppState} = this.props;
    updateAppState({isFirst:false,isLoading:true});
    axios.get(`http://localhost:3000/api1/search/users?q=${keyword}`).then(
      response => updateAppState({users:response.data.items,isLoading:false}),
      error => updateAppState({err:error,isLoading:false})
    )
  };
}

那么我们来代码,当我们拿到用户输入的数据了之后是不是马上要通知App组件更新state说我们要发送请求了,你们不要展示欢迎词了,而且我发送请求你要把Loading展示出来了,然后等请求发送出去之后,如果成功了通知App组件更新state我请求成功了,不要展示Loading了,展示数据吧,失败了也一样,不要展示Loading了,展示错误信息吧。

展示

我们把state的更新逻辑都里清楚了,但是List组件里面应该这么展示呢?首先是不是要把整个state都传给List组件?那么然后呢?

export default class List extends Component {
  render() {
    const { users,isFirst,isLoading,err } = this.props;
    return (
      <div className="row">
        {
          isFirst ? <h2>Welcome! Please input keywords and click search</h2>:
          isLoading ? <h2>Loading......</h2>:
          err ? <h2 style={{color: 'red'}}>{err}</h2>:
          users.map(userObj => (
            <div className="card" key={userObj.id}>
              <a href={userObj.html_url} target="_blank" rel="noreferrer">
                <img alt="head-pic" src={userObj.avatar_url} 
                  style={{ width: "100px" }} />
              </a>
              <p className="card-text">{userObj.login}</p>
            </div>
          ))
        }
      </div>
    )
  }
}

我们来看一下,我们List组件中的东西是不是不能写死啊?因为我们要判断展示什么东西啊,但是jsx语法中能写if判断吗?我们来回顾一下jsx语法规则,jsx可以通过{}来引入的js表达式的支持,而if判断是什么?if判断是语句啊。所以说我们这里得用三元表达式。我们先来判断是不是第一次打开,如果是就展示欢迎词,否则,我们又问了,是不是在Loading?如果是,就展示Loading,否则我们又问,是不是有错误?如果是,那就展示错误信息,否则既不是第一次打开,又不是在Loading,还不是有错误,那就是请求成功了呗,那就展示数据啊。那么我们看一看这个效果对不对:

image-20220112112920345

第一次打开,展示了欢迎词,那么我们搜索一下看看吧

image-20220112113451969

这里Loading也出现了

image-20220112113517055

搜索完之后,数据也成功展示出来了,那么错误是什么样子呢?

image-20220112113742366

页面没出来,而且还报错,这是什么意思?说对象不能直接展示,所以说我们在Search组件中,走到error分支的时候不能存错误对象,而要存error.message那么我们这次再来看:

image-20220112114007367

这样我们的错误信息也出来了

总结

  • 我们通过一个函数来集合多个更改state的操作
  • 不肯用直接展示错误对象,要展示对象信息

Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.

Link of this article:https://work.lynchow.com/article/github_search_finish/