react-搜索框组件

借鉴React文档 “React的编程思想”章节,实现一个类似百度搜索的搜索框组件

文档中的步骤为

  • 构建组件层次
  • 用React构建一个静态版本
  • 确定state的最小表示
  • 确定state的位置
  • 添加反向数据流

一、构建组件层次

结构如下

-SearchBox

    -SearchInput

    -SearchResult

        -SearchResultList

因后续望在下拉框显示“加载中”“已全部加载” “无数据”等加载状态,故在SearchResult组件下,将搜索结果列表组件SearchResultList独立出来,方便后续加入状态组件到SearchResult下


二、构建静态版本

这一步,没有交互,故暂不考虑state,数据通过props从父组件向子组件传递,组件中仅有render()方法,参照文档,定义了一个数据列表,作为props传入顶级组件SearchBox,而后,SearchBox再将其传入需要该列表的子组件,及SearchResult。这里只是用于显示静态界面,编写样式,因后续改为调用Github API获取数据,该定义的数据变量及相关的组件属性最终将被删除。

这一步我采用自上而下的方式构建。

SearchBox定义如下

class SearchBox extends React.Component {
	render() {
		return (
			
); } } var DATASET = [ {name: 'Wanna Be Starting Something', id: '0'}, {name: 'Baby be Mine', id: '1'}, {name: 'The Girl is Mine', id: '2'}, {name: 'Thriller', id: '3'}, {name: 'Beat It', id: '4'}, {name: 'Bilie Jean', id: '5'} ]; ReactDOM.render( , document.getElementById('root') );

SearchResult 和 SearchResultList结构如下

可以看到 SearchResult 将属性 resultList (来自父组件)传递给它的孩子 SearchResultList 的 属性 data。后续SearchResult 会调用API接口,将结果传入SearchResultList ,即SearchResultList 只是拿到数据做渲染。

SearchResultList 渲染列表的方式是调用了map方法,将每一个数据项包装在

  • 元素中,最后返回一个
      列表

      class SearchResultList extends React.Component {
      	render() {
      		const resultItems = this.props.data;
      		const listItems = resultItems.map((item) =>
      			
    • {item.name}
    • ); return (
        {listItems}
      ); } } class SearchResult extends React.Component { render() { return (
      ); } }

      三、确定state的最小表示

      和文档不同的是,后来将数据列表设置为state。原文档的初始数据作为顶级父组件的props传入,筛选结果是初始数据和用户输入计算后得出,而我最终的数据列表是服务器端数据根据用户输入筛选后返回,且是不断变换的,故设计为 SearchResult 的 state

      最终的 state 是:

      • Input 输入框的值
      • 调用API得到的数据
      • loading 状态

      四、state 的位置

      因 SearchInput 需要输入框的值用以显示,SearchResult 需要输入框的值用以请求数据,故将之放在需要它的组件的最小公共父组件里,即 SearchBox。搜索结果列表和 loading状态放在SearchResult下

      五、添加反向数据流

      因输入框的值(props 属性)来自 父组件的 state, 要想输入框响应用户输入,即显示用户的输入,input 需要设置父组件的state, 即将值传递给父组件。实现方式为父组件向子组件传递 props 进行通讯,只是父组件传递的,是作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,即输入框的值,作为参数,传递到父组件的作用域中。

      参考: http://taobaofed.org/blog/2016/11/17/react-components-communication/

      最终代码如下:

      import $ from 'jquery';
      import React from 'react';
      import ReactDOM from 'react-dom';
      import styles from './index.css';
      import registerServiceWorker from './registerServiceWorker';
      
      class SearchResultList extends React.Component {
      	render() {
      		const resultItems = this.props.data;
      		const listItems = resultItems.map((item) =>
      			
    • {item.name}
    • ); return (
        {listItems}
      ); } } class SearchResult extends React.Component { constructor(props) { super(props); this.state = { loading: true, error: null, data: null }; } componentWillUpdate() { $.ajaxSetup({ async: true }); $.getJSON('https://api.github.com/search/repositories?q='+this.props.searchText, (result) => { console.log(typeof(result)); console.log(result.items); this.setState({loading: false, data: result.items}); }); } render() { if(this.state.data) { return (
      ); } else { return (
      ); } } } class SearchInput extends React.Component { constructor(props) { super(props); this.handleSearchTextInputChange = this.handleSearchTextInputChange.bind(this); } handleSearchTextInputChange(e) { this.props.onSearchTextInput(e.target.value); } render() { return (
      ); } } class SearchBox extends React.Component { constructor(props) { super(props); this.state = { searchText: '' }; this.handleSearchTextInput = this.handleSearchTextInput.bind(this); } handleSearchTextInput(searchText) { this.setState({ searchText: searchText }); } render() { return (
      ); } } ReactDOM.render( , document.getElementById('root') ); registerServiceWorker();

      结果如下

      react-搜索框组件_第1张图片

      和在 github 的搜索结果保持一致

      react-搜索框组件_第2张图片


      后续优化:

      1. 将请求 url 提取出来作为props传递给顶级父组件

      2. 增加搜索结果列表的搜索状态样式,分次请求

      3. 还需学习组件生命周期,现数据请求和设置state放在componentWillUpdate中,会造成重复请求的问题。



  • 你可能感兴趣的:(react)