上节课我介绍了在案例中用axios
发送请求,这节课我们来介绍一下List
组件的数据展示。
回顾
在开始这节课的内容之前我们来先对上节课的要点做一个简单回顾
- 解构赋值重命名变量
- 复习一下
ref
- 回顾一下代理的配置
以上便是上节课的主要要点,接下来我们开始这节课的内容。
数据结构分析
我们在拿到数据做页面展示的时候,第一步我是不是要先看到数据长什么样子啊?我们只有知道数据什么样才能分析怎么去展示用户信息啊。
当然了,在公司的开发过程中,我们的数据结构基本都是前后端在一起协商好了的。但是我们目前是不是根本不知道GitHub
会给我们返回什么样的数据?那么我们先来请求看一下数据长什么样子:
首先我们来看,这给我们的是一个对象,里面有 3 个属性,先看第一个incomplete_results
属性,这个属性是什么意思呢?这个属性代表了这次结果GitHub
给我返回的是不是一个完整的结果,我们看我们获取到的数据中这个属性是false
,这就代表我们拿到的不是完整结果,那么为什么呢?因为我们搜索的这个关键词在GitHub
上的结果实在太多了,不可能一次性全都给你返回,但是总共有多少,而又返回多少呢?
我们看到了有一个total_count
是代表总量有多少个,这里是 18 个,items
属性也告诉我们这次返回的数量是 18 个。可能有人要问了,这不是完整的吗?为啥incomplete_results
却是false
呢?其实这个其实在GitHub
的接口中并没有对这个属性做处理,默认就是false
。
那我们在展开看items
里面的每个用户对象:
这里的属性是不是太多了啊,我们不可能说每个属性都说一遍,我们挑我们页面上需要用的东西,首先我们页面上是不是要展示头像?是不是还要有用户名?而且我们还要让头像可以点击跳转到这个用户的主页,那么我们来看应该用什么属性?是不是这三个?
avatar_url
login
html_url
数据存放位置分析
那么好,我们现在第一已经能够拿到数据了,第二我们已经分析出数据中我们需要什么数据了,那么好我们来分析一下数据存放到哪呢?
第一,我们的数据是谁发送请求获取的?是不是Search
组件?第二,我们获取到数据之后要交给谁去展示?是不是List
组件?Search
组件和List
组件是什么关系?是不是平级的?那么我们能不能直接通过Seatch
组件直接把数据给List
?以我们目前的知识面来看是不是不行?那么是不是要通过父组件来中转?父组件是谁?是不是App
组件?那么好,我们是不是要把数据存放在App
组件中?
既然在App
组件中存数据,而数据是App
组件的子组件给的,是不是要App
组件提供一个入口函数给子组件
?话分两头,App
组件中哪里可以存数据呢?是不是state
和props
以及自身属性啊?我们说过props
是只读的,我们只能通过组件标签传入,不能在组件内部以任何形式修改,那么props
是不是我们就不考虑了?因为我们是从子组件拿数据的啊,子组件不可能给父组件的组件标签传props
的啊。那么自身属性行不行呢?我们是不是要把数据展示到页面上啊?所以说当我们搜索之后是不是要触发页面更新的啊?自身属性能驱动页面更新吗?不能啊,那我们就只能选state
了啊。
数据交互
我们上面已经分析过了,我们要把数据存放在App
组件的state
中,而且还要提供一个入口函数给Search
组件,用于Search
组件来更新App
组件的state
。那么好,我们来看一下:
export default class App extends Component { state = { users: [] }; saveUsers = users => this.setState({ users }); render() { return ( <div className="container"> <Search saveUsers={this.saveUsers} /> <List /> </div> ) } }
我们的App
组件既然要用state
来存放数据,那么是不是就要初始化state
?给定一个属性是users
而且是个空数组。
然后我们要定义一个入口函数啊,还记不记得TodoList
案例中的结论?state
在哪,修改state
的方法就在哪,所以我们定义入口函数也一定是在App
组件中的。那么好,我们看我们定义了一个saveUsers
方法,这个方法接收users
参数,这个参数就是一个数组,然后我们来修改state
,而我们接收的参数和state
中的属性重名,所以可以简写。
最后我们在渲染子组件的时候,通过Search
组件标签属性将入口函数传给了Search
组件。
那么我们初始化了state
而且也提供了入口函数并传给了Search
组件,那么在Search
组件中我们就要来调用这个方法啊:
export default class Search extends Component { render() {...} search = () => { const { value: keyword } = this.user; axios.get(`http://localhost:3000/api1/search/users?q=${keyword}`).then( response => { this.props.saveUsers(response.data.items); }, error => { console.log(error); } ) }; }
这就简单了,其他的都不用边,我们之前请求成功是把我们的数据打印到控制台上,现在我们不需要打印了,那么我们就调用props
中收到的saveUsers
函数来把数据存到App
组件的state
中去啊,但是我们state
中的users
属性是不是一个数组啊?而数据中的items
属性刚好就是一个数组,那么我们直接把这个items
属性传给saveUsers
函数就可以了,那么我们来看一下效果吧:
我们在搜索之前,我们的state
的users
属性是一个空数组,那么我们来搜索一下再看:
这一次数据是不是来了?那么好,数据我们是拿到了,但是还没有展示到页面上啊。我们接下来是不是就要把state
中的users
传给List
组件啊?那么好,App
和List
是什么关系?是不是父子关系?App
是父组件,List
是子组件,父组件给子组件传数据怎么传?是不是直接通过props
就行了?那么我们来处理一下:
// App 组件 export default class App extends Component { state = { users: [] }; saveUsers = users => this.setState({ users }); render() { const { users } = this.state; return ( <div className="container"> <Search saveUsers={this.saveUsers} /> <List users={users}/> </div> ); } } // List 组件 export default class List extends Component { render() { const { users } = this.props; return ( <div className="row"> { users.map(userObj => ( <div className="card"> <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> ); } }
我们来看一下代码,首先App
组件中没有什么可说的,就是把users
传给了List
组件,那么List
组件中呢,我们先是解构赋值拿到了users
,然后遍历数组来生成我们的固定结构。那么我们来看一下效果吧:
最初始肯定是什么都没有,因为我们初始化的state
是个空数组,那么我们来搜索一下看看:
数据也都出来了,展示也没有问题,来看一下控制台:
页面展示倒是没有任何问题。但是控制台里面是不是有一个错误警告啊?告诉我们没有设置唯一的key
,那么我们设一个呗?那么我们用什么来做key
?我们回想一下我们的数据:
这个数据中是不是有一个id
属性啊?那我们用id
来做key
不就行了嘛
这次再来看,就没有刚才的警告了。
以上便是我们List
组件展示的内容
总结
- 平级组件共用的数据存放在公共父组件的
state
中 - 遍历一定要加上唯一性
key
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_show_data/