上节课我们介绍了如何在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:"" }; ... }
首先我们要初始化我们的state
,users
我们就不多说了,来看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
属性,如果失败了,要把error
给err
属性,那么在这之后我们还展示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
,还不是有错误,那就是请求成功了呗,那就展示数据啊。那么我们看一看这个效果对不对:
第一次打开,展示了欢迎词,那么我们搜索一下看看吧
这里Loading
也出现了
搜索完之后,数据也成功展示出来了,那么错误是什么样子呢?
页面没出来,而且还报错,这是什么意思?说对象不能直接展示,所以说我们在Search
组件中,走到error
分支的时候不能存错误对象,而要存error.message
那么我们这次再来看:
这样我们的错误信息也出来了
总结
- 我们通过一个函数来集合多个更改
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/