天天看點

react ant-design架構 基于hook 的表格分頁查詢

之前用react的做的項目一直都是用class ,setState,componentDidMount ,componentDidUpdate ,componentWillUnmount 的寫法,但從16.8以來,react新增了Hook特性,對于喜歡技術嘗試我的來說,豈能不試一下新寫法。

我們一般用react 的ant-design架構做背景管理系統,那麼最常見的業務場景就是表格,查詢,分頁。下面我就拿最常用的一個例子和大家分享一下:

首先請看我們的界面:

react ant-design架構 基于hook 的表格分頁查詢

上面是搜尋條件,中間是表格,下面是分頁。這個大家一眼就能看懂,那麼我就來給大家上代碼

//注意這個js代碼整個對應上面的UI展示,是我們項目裡的一個頁面,裡面部分字段可能大家可能用不上。

import React, { useCallback, useEffect, useState} from 'react';
import {Collapse, Table, Button, Space, Form, Input, Select, DatePicker,} from 'antd';

//注意此處是我們請求接口後傳回的資料,這裡我是把所有的api請求都提出來了,下面filterUser和getList就是我們這個頁面需要用到的api
import {filterUser, getList} from "../../service/user";

//moment是為了時間選擇器,選擇後進行時間格式化所用
import moment from 'moment';
import 'moment/locale/zh-cn';

//locale是為了中文化時間控件的,如果其他的控件是非中文的,也可以按照這個寫法中文化
import locale from 'antd/es/locale/zh_CN';

//引入本頁面的樣式檔案
import "./list.css";

const {Panel} = Collapse;
const {Option} = Select;
const {RangePicker} = DatePicker;

function List() {

   //設定頁碼
  let [page,setPage] = useState(1);

  //設定每頁條數
  let size = 2;

  //設定總頁數
  const [total,setTotal] = useState(0);

  //搜尋條件
  let filter = {
    mobile:'',
    nickname:'',
    channel_id:0,
    tag_key:'',
    min_create_time:0,
    max_create_time:0,
  };

  //請求資料時loading狀态
  const [load,setLoad] = useState(false);

  //表格資料
  const [tableData,setTableData] = useState([]);


  //此處是為了初始化時候請求一次資料
  useEffect(()=>{
    pageChange(page,size);
  },[])


  //點選下面的分頁按鈕觸發的方法
  const pageChange = useCallback(
    (currentPage,currentSize)=>{
      // debugger
      console.log(currentPage,currentSize,"1")
      page = currentPage === undefined ? page : currentPage;
      setPage(page);
      size = currentSize === undefined ? size : currentSize;
      fetchData();
    },
    []
  )

  //點選搜尋按鈕觸發的方法
  const searchData = useCallback(
    (values)=>{
      // debugger
      console.log(values)
      filter.mobile = values && values.mobile !== undefined ? values.mobile : '';
      filter.nickname = values && values.nickname !== undefined ? values.nickname : '';
      filter.channel_id = values && values.channel_id !== undefined ? values.channel_id : 0;
      filter.tag_key = values && values.tag_key !== undefined ? values.tag_key : '';
      if(values && values.create_time !== undefined){
        let min_create_time = parseInt(moment(values.create_time[0]).valueOf()/1000);
        let max_create_time = parseInt(moment(values.create_time[1]).valueOf()/1000);
        filter.min_create_time = min_create_time;
        filter.max_create_time = max_create_time;
      }else{
        filter.min_create_time = 0;
        filter.max_create_time = 0;
      }
      page = 1;
      setPage(page);
      console.log("search",page,size)
      console.log("search filter",filter)
      fetchData();

    },[]
  )

  //Api請求背景接口的方法
  const fetchData = async()=> {
    setLoad(true);
    let params = {page, size, ...filter};
    let result = await getList(params);
    setLoad(false);
    if (result.code === 0) {
      result = result.data;
      console.log("result", result);
      let table = [...result.list];
      setTotal(result.total_size);
      setTableData([...table]);
      console.log("table", table)
    }
  }


  //表頭列
  const columns = [
    {
      title: '使用者ID',
      dataIndex: 'id',
    },
    {
      title: '昵稱',
      dataIndex: 'nickname',
    },
    {
      title: '手機号',
      dataIndex: 'mobile',
    },
    {
      title: '來源管道',
      dataIndex: 'reg_channel_desc',
    },
    {
      title: '注冊時間',
      dataIndex: 'create_time_desc',
    },
  ];

  //擷取搜尋條件的api
  const [user_channel,setUser_channel] = useState([]);
  const [user_tag,setUser_tag] = useState([]);
  useEffect(()=>{
    let params = {
      show_user_tag:true,
      show_user_channel:true,
      show_user_identifier:true,
    };
    const fetchData = async ()=>{
      const result = await filterUser(params);
      if(result.code === 0){
        const userChannel = result.data&&result.data.user_channel ? result.data.user_channel : [];
        const userTag = result.data&&result.data.user_tag ? result.data.user_tag : [];
        setUser_channel(userChannel);
        setUser_tag(userTag);
      }
    }
    fetchData();
  },[])


  //重置表單
  const [form] = Form.useForm();
  const reset = ()=>{
    form.resetFields();
    //此處尤其要注意,resetFields表單重置後會重新mount元件,是以不必在這裡重新調用請求api的接口。
    //重置之後,會自動調用搜尋清單的方法。
  }

  return (
    <div>
      <h1>使用者清單</h1>
      <Collapse defaultActiveKey={['1']} style={{marginBottom:'20px'}}>
        <Panel header="搜尋條件" key="1">
          <Form className="list"
                autoComplete="off"
                layout="inline"
                name="basic"
                form={form}
                initialValues={{remember: true}}
                onFinish={searchData}
          >
            <Form.Item
              label="手機号"
              name="mobile"
            >
              <Input allowClear/>
            </Form.Item>
            <Form.Item
              label="昵稱"
              name="nickname"
            >
              <Input allowClear/>
            </Form.Item>
            <Form.Item
              label="使用者标簽"
              name="tag_key"
            >
              <Select
                showSearch allowClear
                style={{width: 200}}
                placeholder="選擇使用者标簽"
                optionFilterProp="children"
                filterOption={(input, option) =>
                  option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
                }
              >
                {
                  user_tag.map((item, i) => {
                    return (
                      <Option value={item.key} key={item.key}>{item.val}</Option>
                    )
                  })
                }
              </Select>
            </Form.Item>
            <Form.Item
              label="來源管道"
              name="channel_id"
            >
              <Select
                showSearch allowClear
                style={{width: 200}}
                placeholder="選擇來源管道"
                optionFilterProp="children"
                filterOption={(input, option) =>
                  option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
                }
              >
                {
                  user_channel.map((item, i) => {
                    return (
                      <Option value={item.key} key={item.key}>{item.val}</Option>
                    )
                  })
                }
              </Select>
            </Form.Item>
            <Form.Item
              label="注冊時間"
              name="create_time"
            >
              <RangePicker locale={locale}/>
            </Form.Item>
            <Form.Item>
              <Button type="primary" htmlType="submit">
                查詢
              </Button>
              <Button htmlType="submit" className="reset" onClick={reset}>
                重置
              </Button>
            </Form.Item>
          </Form>
        </Panel>
      </Collapse>
      <Table rowKey="id" columns={columns} loading={load}
             dataSource={tableData} bordered
             scroll={{y: 500}}
             rowSelection={{selectedRowKeys: []}}
             pagination={{showSizeChanger:true,onChange:pageChange,
               pageSizeOptions:['2','5','10'],defaultPageSize:size,
               showTotal: ()=>{return `共${total}條資料`},
               current:page,total:total}}
      />
    </div>
  );
}

export default List;
           

既然大家使用hook寫東西了,那麼關于hook的一些知識肯定也有一些了解,很多文章和部落格也有介紹,這裡我就不多說了,下面為大家附上官網位址:react hook官網位址

這是我在項目裡能想到的一個寫法,如果大家有更好的寫法,歡迎和我分享。非常樂意和大家一起學習,一起進步。