React Hooks实现模糊搜索demo(ZUCC智能终端与移动应用开发lab6)

分析ReactInAction01示例的数据状态控制和组件关系

组件关系

在这里插入图片描述

数据状态控制

在这里插入图片描述

在这里插入图片描述

完整代码

App.js

import React, { Component } from 'react';
import Table from './lab1/table'
import './lab1/table.css'
function App() {
  return ( 
    <>
      <Table></Table>
    </>
   );
}
export default App;

table.js

import React ,{useState} from 'react';
import TableHeader from './tableHeader'
import TableBody from './tableBody'
import Form from './form';
function Table() {
  const [person,setPerson] = useState([
    {name:'zjx',job:'teacher'},
    {name:'zs',job:'student'}
  ])
  const deleteItem = (index)=>{
    console.log("收到删除操作"+index)
    console.log(person[index])
    setPerson(()=>person.filter((item,i)=>i!=index)
    )
  }
  const addItem = (item)=>{
    console.log("成功接收到数据");
    console.log(item);
    setPerson(()=>{
      return[
        ...person,item
      ]  //这里返回的是一个数组,一开始以为是对象,所以一直报错
    })
  }
  return (
    <>
      <table>
        <TableHeader></TableHeader>
        <TableBody 
          person = {person} 
          deleteItem = {deleteItem}
        >

        </TableBody>
      </table>
      <Form addItem = {addItem}></Form>
    </>
    
    
  )
  
}

export default Table;

tableHeader

import React from 'react';

function TableHeader() {
  return ( 
    <thead>
        <tr>
          <th>Name</th>
          <th>Job</th>
          <th>操作</th>
        </tr>
      </thead>
   );
}

export default TableHeader;

tableBody.js

import React ,{useState} from 'react'
function TableBody(props) {
  // const state  = [{name:'zjx',job:'teahcer'}]
  // const person = useContext(PersonValue)
  // const [person,setPerson] = useState(props.character)
  const removeItem = (index)=>{
    props.deleteItem(index)
  }
  const rows = props.person.map((item,index) =>{
    return (
        <tr key={index}>
          <th>{item.name}</th>
          <th>{item.job}</th>
          <th> <button onClick = {()=>removeItem(index)}>移除</button> </th>
        </tr>
    )
  })
 
  
  return ( 
    <tbody>
       {rows} 
    </tbody>
   );
}

export default TableBody;

form.js

import React,{useState} from 'react';
function Form(props) {
  const [form,setForm] = useState({name:'',job:''})
  const handleChange = (e)=>{
    const target  = e.target;
    console.log(e);
    setForm(()=>{
      return {
        ...form,
        [target.name]:target.value,  //key-value key是target.value所对应的属性名
      }
    })
    console.log(form);
  }
  // console.log(props)
  const submitAdd = ()=>{
    // console.log(111);
    props.addItem(form);
  }
  return ( 
    
    <form>
      {/* <p>{form.name}</p> */}
      <label htmlFor="name">Name</label>
      <input type="text" name="name" placeholder="请输入姓名" value={form.name} onChange={(e)=>handleChange(e)} />
      <label htmlFor="job">Job</label>
      <input type="text" name="job" placeholder="请输入工作" value={form.job}  onChange={(e)=>handleChange(e)}/>
      <button type = "button" onClick = {submitAdd}>submit</button>  
      {/* 这里必须设置一下button的类型不然会默认为submit导致刷新页面 */}
    </form>
   );
}

export default Form;

table.css

存放所有组件的css

table{
  border-collapse: collapse;
  border-spacing: 0;
  width: 100%;
  max-width: 100%;
}

thead th{
  border-bottom: 2px solid #dedede;
}

tbody th{
  border-bottom: 2px solid #dedede;
}
td{
  border-bottom: 1px solid #dedede;
}
th,td{
  text-align:left;
  padding: .5rem;
}

button{
  background-color: pink;
}


form{
  width: 100%;
  height: 20%;
  display: flex;
  flex-direction: column;
  text-align: left;
}

label{
  display:block;
  width: 100%;
  /* margin-bottom: .5rem; */
}

input{
  margin: .5rem 0 ;
  width: 70%;
  height: 6vh;
}

form button {
  width: 10rem;
  height: 2rem;
  font-size: 1rem;
}

一些知识点和坑

useState中setState的返回值(添加元素)

我定义表单的状态值为一个数组,他的单个元素是一个对象

{
	name:'',
	job:''
}

那么在调用setPerson返回的时候就要返回对应的数据类型——数组

const addItem = (item)=>{
    console.log("成功接收到数据");
    console.log(item);
    setPerson(()=>{
      return[
        ...person,item
      ]  //这里返回的是一个数组,一开始以为是对象,所以一直报错
    })
  }

其中…person是将这个数组解构,后面添加新元素item

这是react中添加新元素的惯用手法

useState中通过set函数删除元素

子组件调用父组件删除元素的函数,同时传入要删除元素的下标

<th> <button onClick = {()=>removeItem(index)}>移除</button> </th>

父组件通过filter函数遍历元素,返回一个新的数组,作为setPerson的新的状态值返回

const deleteItem = (index)=>{
    console.log("收到删除操作"+index)
    console.log(person[index])
    setPerson(()=>person.filter((item,i)=>i!=index)
    )
  }

可以写成这样看起来更直观

setPerson(()=>{
	return person.filter((item,i)=>{
		return i!=index
	})
})

useState中input的双向绑定

不同的是useState定义的状态变量是一个对象形式

<input type="text" name="name" placeholder="请输入姓名" value={form.name} onChange={(e)=>handleChange(e)} />

 <input type="text" name="job" placeholder="请输入工作" value={form.job}  onChange={(e)=>handleChange(e)}/>
const handleChange = (e)=>{
    const target  = e.target;
    console.log(e);
    setForm(()=>{
      return {
        ...form,
        [target.name]:target.value,  //key-value key是target.value所对应的属性名
      }
    })
    console.log(form);
  }

返回一个对象,将form的对象解构,同时返回一个属性(name或者job)覆盖form中的name或job以此达到更新的目的

setForm(()=>{
      return {
        ...form,
        [target.name]:target.value,  //key-value key是target.value所对应的属性名
      }
    

对象是key-value形式,这种写法就是根据value值找到对应的key,以此进行赋值

也就是说我们在name的输入框中输入zjx,那么target.value就是value(zjx),他所对应的key就是input所绑定的name属性也就是target.name(name)

[target.name]:target.value,  //key-value 

函数式组件

const rows = props.person.map((item,index) =>{
    return (
        <tr key={index}>
          <th>{item.name}</th>
          <th>{item.job}</th>
          <th> <button onClick = {()=>removeItem(index)}>移除</button> </th>
        </tr>
    )
  })

button点击之后刷新页面

<button type = "" onClick = {submitAdd}>submit</button>  

一开始这么写提交按钮,没有表明type的类型,它默认为我们问submit类型,会刷新网页

改成下述写法

<button type = "button" onClick = {submitAdd}>submit</button> 

编写如下程序SearchStudentApp:

a.程序包含一个学生列表页,页面中有一个搜索框,一个搜索按钮,一个数据显示表(包含学生学号、姓名、性别、班级四列),一个数据生成按钮

b.初始化时数据列表为空

c.点击数据生成按钮自动生成50行数据

d.在输入框中可以按照学生姓名模糊检索列表数据,并且更新表格为只显示符合检索条件的数据

使用json生成器快速生成50条数据

JSON Generator – Tool for generating random data (json-generator.com)

完整代码

studentTable.js

import React,{useState,useEffect} from 'react';
import TableBody from './TableBody';
import TableHeader from './TableHeader';
import SearchInput from './SearchInput'
function StudentTable() {
  const [data,setData] = useState([
    {}
    
  ])
  const [init,setInit] = useState([
    {}
    
  ]);
  const loadData = (d)=>{
    console.log("收到数据")
    setData(d);
    console.log(data);
    setInit(d); //定义初始化数据
  }
  const search = (searchName)=>{
    console.log("接收到搜索");
    console.log(searchName);
    setData(()=>init.filter((item)=>{ //在初始化数据中搜索 保证一直是全局搜索
      return item.name.toLowerCase().indexOf(searchName.toLowerCase())>=0}))
  }
  return ( 
    <>
    <SearchInput loadData = {loadData} search = {search}></SearchInput>
    <table>
    <TableHeader></TableHeader>
    <TableBody data = {data} ></TableBody>
    </table>
    
    </>
    
   );
}

export default StudentTable;

searchInput.js

import React,{useState} from 'react';
// import '../../public/data.json'
function SearchInput(props) {
  const data = 
     [
      {
        id: 32001682,
        name: "Rachel",
        gender: "female",
        class: "2003"
      },
      {
        id: 32001858,
        name: "Mona",
        gender: "female",
        class: "2001"
      },
      {
        id: 32001592,
        name: "Gwendolyn",
        gender: "female",
        class: "2002"
      },
      {
        id: 32001487,
        name: "Mcfadden",
        gender: "male",
        class: "2001"
      },
      {
        id: 32001862,
        name: "Coleen",
        gender: "female",
        class: "2003"
      },
      {
        id: 32001729,
        name: "Austin",
        gender: "male",
        class: "2004"
      },
      {
        id: 32001352,
        name: "Vickie",
        gender: "female",
        class: "2002"
      },
      {
        id: 32001613,
        name: "Finley",
        gender: "male",
        class: "2002"
      },
      {
        id: 32001983,
        name: "Mandy",
        gender: "female",
        class: "2003"
      },
      {
        id: 32001063,
        name: "Barton",
        gender: "male",
        class: "2002"
      },
      {
        id: 32001323,
        name: "Melanie",
        gender: "female",
        class: "2002"
      },
      {
        id: 32001424,
        name: "Leticia",
        gender: "female",
        class: "2001"
      },
      {
        id: 32001679,
        name: "Candace",
        gender: "female",
        class: "2004"
      },
      {
        id: 32001417,
        name: "Cleo",
        gender: "female",
        class: "2001"
      },
      {
        id: 32001221,
        name: "Cathy",
        gender: "female",
        class: "2002"
      },
      {
        id: 32001906,
        name: "Angelita",
        gender: "female",
        class: "2001"
      },
      {
        id: 32001338,
        name: "Buchanan",
        gender: "male",
        class: "2001"
      },
      {
        id: 32001348,
        name: "Lenora",
        gender: "female",
        class: "2001"
      },
      {
        id: 32001434,
        name: "Inez",
        gender: "female",
        class: "2002"
      },
      {
        id: 32001691,
        name: "Jewell",
        gender: "female",
        class: "2002"
      },
      {
        id: 32001616,
        name: "Lesley",
        gender: "female",
        class: "2003"
      },
      {
        id: 32001567,
        name: "Dunn",
        gender: "male",
        class: "2004"
      },
      {
        id: 32001902,
        name: "Hall",
        gender: "male",
        class: "2004"
      },
      {
        id: 32001418,
        name: "Jacquelyn",
        gender: "female",
        class: "2004"
      },
      {
        id: 32001618,
        name: "Nichole",
        gender: "female",
        class: "2003"
      },
      {
        id: 32001039,
        name: "Carly",
        gender: "female",
        class: "2004"
      },
      {
        id: 32001483,
        name: "Barker",
        gender: "male",
        class: "2001"
      },
      {
        id: 32001651,
        name: "Randall",
        gender: "male",
        class: "2002"
      },
      {
        id: 32001925,
        name: "Madeleine",
        gender: "female",
        class: "2003"
      },
      {
        id: 32001794,
        name: "Kathie",
        gender: "female",
        class: "2002"
      },
      {
        id: 32001843,
        name: "Lavonne",
        gender: "female",
        class: "2004"
      },
      {
        id: 32001714,
        name: "Bond",
        gender: "male",
        class: "2002"
      },
      {
        id: 32001196,
        name: "Kasey",
        gender: "female",
        class: "2004"
      },
      {
        id: 32001658,
        name: "Jeanie",
        gender: "female",
        class: "2001"
      },
      {
        id: 32001500,
        name: "Bentley",
        gender: "male",
        class: "2004"
      },
      {
        id: 32001285,
        name: "Millie",
        gender: "female",
        class: "2004"
      },
      {
        id: 32001531,
        name: "Bonita",
        gender: "female",
        class: "2004"
      },
      {
        id: 32001449,
        name: "Millicent",
        gender: "female",
        class: "2002"
      },
      {
        id: 32001049,
        name: "Jenna",
        gender: "female",
        class: "2004"
      },
      {
        id: 32001374,
        name: "Rowena",
        gender: "female",
        class: "2001"
      },
      {
        id: 32001966,
        name: "Kenya",
        gender: "female",
        class: "2003"
      },
      {
        id: 32001131,
        name: "Aida",
        gender: "female",
        class: "2001"
      },
      {
        id: 32001010,
        name: "Oneill",
        gender: "male",
        class: "2004"
      },
      {
        id: 32001070,
        name: "Schultz",
        gender: "male",
        class: "2004"
      },
      {
        id: 32001419,
        name: "Aguirre",
        gender: "male",
        class: "2002"
      },
      {
        id: 32001684,
        name: "Sweet",
        gender: "male",
        class: "2002"
      },
      {
        id: 32001931,
        name: "Maritza",
        gender: "female",
        class: "2003"
      },
      {
        id: 32001376,
        name: "Kelley",
        gender: "male",
        class: "2003"
      },
      {
        id: 32001800,
        name: "Charlotte",
        gender: "female",
        class: "2003"
      },
      {
        id: 32001344,
        name: "Reyna",
        gender: "female",
        class: "2001"
      }
    ]
  const [searchName,setSearch] = useState('')
    
  const getData = ()=>{
    console.log(data);
    pullData(data);
    //  fetch('D:\react-project\reactStudy\public\data.json')
    // .then(response=>response.json())
    // .then(response =>{console.log(response)})
  } 
  const pullData = (d)=>{
    props.loadData(d);
  }
  const handleChange = (e)=>{
    console.log(e.target.value)
    setSearch(e.target.value);
  }
  const handleSearch = ()=>{
    console.log("pull")
    props.search(searchName)
  }
  return ( 
    <div className="search">
      <input type="text" name="searchName" value={searchName} onChange={(e)=>handleChange(e)}/>
      <button type="button" onClick={()=>handleSearch()} >搜索数据</button>
      <button onClick={()=>getData()}>生成数据</button>
    </div>
    
   );
}

export default SearchInput;

tableHeader.js

function TableHeader() {
  return ( 
    <thead>
      <tr>
        <th>学号</th>
        <th>姓名</th>
        <th>性别</th>
        <th>班级</th>
      </tr>
    </thead>
    );
}

export default TableHeader;

tableBody.js

function TableBody(props) {
  const rows = props.data.map((item,index)=>{
    return (
      <tr key={index}>
        <td>{item.id}</td>
      <td>{item.name}</td>
      <td>{item.gender}</td>
      <td>{item.class}</td>
      </tr>
      
    )
  })
  return ( 
    <tbody>
      {rows}
    </tbody>
   );
}

export default TableBody;

效果

在这里插入图片描述

点击生成数据:

在这里插入图片描述

查找:
在这里插入图片描述

遇到的坑

json

生成的json导入有问题,为了简便,将数据直接定义在组件中

模糊搜索

将搜索的字符和数据库中的字符统一转化成小写toLowCase()

连续搜索

连续搜索应该一直是全局搜索,但是一开始的写法,每次搜索都是在上一次搜索到的数据基础上再进行搜索,这导致数据越来越少

解决方法就是定义一个初始状态数据存放所有数据,初次导入数据data和init的值都一样,搜索的时候在init中搜索

const [data,setData] = useState([
    {}
    
  ])
  const [init,setInit] = useState([
    {}
    
  ]);
setData(()=>init.filter((item)=>{ //在初始化数据中搜索 保证一直是全局搜索
      return item.name.toLowerCase().indexOf(searchName.toLowerCase())>=0}))

setState的解构问题

因为数据是以数组的形式存储,同时每个单元都是一个对象

如果setState()传入的元素和定义状态值的数据类型相同就不需要解构

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值