react電商商品列表的實(shí)現(xiàn)流程詳解
整體頁面效果
項(xiàng)目技術(shù)點(diǎn)
- antd組件庫,@ant-design/icons antd的圖標(biāo)庫
- axios 接口請求,攔截器配置
- node-sass sass-loader css樣式的一個嵌套
- react-router-dom react路由使用
- react-redux redux
- hooks:大多數(shù)我們用的是函數(shù)組件,函數(shù)組件沒有state屬性,所以我們使用hooks來初始化數(shù)據(jù),并且函數(shù)組件沒有生命周期
攔截器的配置
由于我們登錄成功之后,需要我們獲取到token令牌之后,我們才能獲取到數(shù)據(jù),如果每個頁面都需要獲取一次token,代碼比較啰嗦,所以我們配置了一個攔截器
需要授權(quán)的 API ,必須在請求頭中使用 Authorization
字段提供 token
令牌
//配置攔截器 import axios from "axios"; //2. 創(chuàng)建對象 const Server = axios.create({ baseURL:"http://api.xiaohuihui0728.cn:8888/api/private/v1/",//基地址 timeout:5000, }) //3. 請求攔截器 Server.interceptors.request.use((config)=>{ //前置攔截器請求發(fā)送出去之前觸發(fā) console.log(config); //增加一個token值 let token = sessionStorage.getItem("token"); config.headers["Authorization"] = token; return config; },(err)=>Promise.reject(err)); //4. 響應(yīng)攔截器 Server.interceptors.response.use((response)=>{ //請求成功,服務(wù)端返回數(shù)據(jù)到客戶端之前觸發(fā) return response.data; },(err)=>Promise.reject(err)) //5.拋出Serve對象的內(nèi)容 export default Server;
主頁面
我們的數(shù)據(jù)寫在columns里面,在里面的dataIndex綁定我們獲取到的數(shù)據(jù)
const columns = [ { title: '商品名稱', dataIndex: 'goods_name', key: 'username', }, { title: '商品價格', dataIndex: 'goods_price', key: 'email', }, { title: '商品重量', dataIndex: 'goods_weight', key: 'mobile', }, { title: '創(chuàng)建時間', dataIndex: 'goods_state', key: 'role_name', }, { title: '操作', key: 'action', render: (_, record) => { return ( <> <Button type="primary" size="small" onClick={() => { showedit(record.goods_id) }}> <EditOutlined /> </Button> <Button type="primary" size="small" danger onClick={() => { delGoods(record.goods_id) }} > <DeleteOutlined /> </Button> </> ) } } ]; const [userData, setUserData] = useState([]) // 初始化數(shù)據(jù) useEffect(() => { getUserData() setPage(1) }, [search, page, pageSize]) // 初始化請求數(shù)據(jù) 用戶 const getUserData = async () => { console.log(pageSize); console.log(search); console.log(page); let { data } = await axios.get(`goods?pagenum=${page}&query=${search}&pagesize=${pageSize}`) console.log(data.goods); if (data) { setTotal(data.total); setUserData(data.goods); } } <Table pagination={false} bordered dataSource={userData} columns={columns} rowKey={(record) => record.goods_id} />
添加商品
添加彈出對話框,添加里面有一個上傳圖片,我們上傳的圖片有一個單獨(dú)的添加接口,所以我們使用action屬性綁定我們要上傳的路徑,headres獲取token,使用onChange獲取圖片上傳的路徑,然后在我們點(diǎn)擊提交form表單數(shù)據(jù)時把圖片臨時地址添加成功
// 添加彈窗狀態(tài) const [addIsModalVisible, setAddIsModalVisible] = useState(false); // 存圖片 let [img,setimg] = useState(""); // 添加取消 const addHandleCancel = () => { setAddIsModalVisible(false); }; //獲取token let token = sessionStorage.getItem("token"); // 添加商品 const onAdd = async (value)=>{ console.log(value); let pics = [{pic:img}]; let data= await axios.post("goods",{...value,pics}) setAddIsModalVisible(false); getUserData() } //圖片上傳 const success = (info)=>{ if(info.file.status==="done"){ console.log(info.file.response.data.tmp_path); setimg(info.file.response.data.tmp_path) } } <Modal title="商品添加" visible={addIsModalVisible} footer={null} ref={addFormRef}> <Form name="basic" labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} initialValues={{ remember: true }} onFinish={onAdd} onFinishFailed={onFinishFailed} autoComplete="off" > <Form.Item label="商品名稱" name="goods_name" rules={[{ required: true, message: '請輸入商品名稱' }]} > <Input /> </Form.Item> <Form.Item label="商品價格" name="goods_price" rules={[{ required: true, message: '請輸入商品價格' }]} > <Input /> </Form.Item> <Form.Item label="商品數(shù)量" name="goods_number" rules={[{ required: true, message: '請輸入商品數(shù)量' }]} > <Input /> </Form.Item> <Form.Item label="商品重量" name="goods_weight" rules={[{ required: true, message: '請輸入商品重量' }]} > <Input /> </Form.Item> <Form.Item label="商品圖片" name="pics" > <Upload {...props} action='http://api.xiaohuihui0728.cn:8888/api/private/v1/upload' headers={{"Authorization":token}} onChange={success} listType='picture'> <Button type='primary'>上傳圖片</Button> </Upload> </Form.Item> <Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 16 }}> <Button type="primary" htmlType="submit" > Submit </Button> <Button type="primary" onClick={() => { (addHandleCancel()) }} danger> 取消 </Button> </Form.Item> </Form> </Modal> <Button type="primary" onClick={showModal}> <EditOutlined /> 添加商品 </Button>
分頁與搜索
我們在獲取數(shù)據(jù)的時候,就獲取我們的分頁條數(shù)和總數(shù)以及搜索的關(guān)鍵字,然后在分頁中進(jìn)行數(shù)據(jù)屬性的配置即可
// 搜索 let [search, setSearch] = useState("") // 總條數(shù) let [total, setTotal] = useState(0) // 當(dāng)前頁 let [page, setPage] = useState(1) // 每頁條數(shù) let [pageSize, setPageSize] = useState(2) // 搜索 const onSearch = (val) => { setSearch(val) } // 分頁 const onChange = (page, pageSize) => { setPage(page) setPageSize(pageSize) } // 初始化請求數(shù)據(jù) 用戶 const getUserData = async () => { console.log(pageSize); console.log(search); console.log(page); let { data } = await axios.get(`goods?pagenum=${page}&query=${search}&pagesize=${pageSize}`) console.log(data.goods); if (data) { setTotal(data.total); setUserData(data.goods); } } <Search allowClear placeholder="input search text" onSearch={onSearch} enterButton style={{ width: 300, height: 60 }} /> <Pagination className='pagination' total={total} showSizeChanger showQuickJumper pageSizeOptions={[10, 20, 30]} defaultPageSize={2} showTotal={(total) => `Total ${total} items`} onChange={onChange} />
修改商品
我們在點(diǎn)擊修改彈出對話框的同時,需要把數(shù)據(jù)綁定到輸入框內(nèi),我們利用formRef.current.setFieldsValue進(jìn)行數(shù)據(jù)回填,然后請求修改接口即可
// 修改彈出框 const [isModalVisible, setIsModalVisible] = useState(false); // 修改彈出框,數(shù)據(jù)回填 const showedit = async (e) => { setIsModalVisible(true); setgoodid(e) let { data } = await axios.get(`goods/${e}`) console.log(data); formRef.current.setFieldsValue({ goods_name: data.goods_name, goods_price: data.goods_price, goods_number: data.goods_number, goods_weight: data.goods_weight }) }; // 修改取消按鈕 const editHandleCancel = () => { setIsModalVisible(false) } // 修改商品 const onFinish = async (values) => { let { meta } = await axios.put(`goods/${goodid}`, { goods_name: values.goods_name, goods_number: values.goods_number, goods_price: values.goods_price, goods_weight: values.goods_weight }) // console.log(data); if (meta.status === 200) { message.success(meta.msg) setIsModalVisible(false); getUserData() } else { message.info(meta.msg) setIsModalVisible(false); } }; <Button type="primary" size="small" onClick={() => { showedit(record.goods_id) }}> <EditOutlined /> </Button> {/* 修改彈出框 */} <Modal title="修改商品" visible={isModalVisible} footer={null}> <Form name="basic" labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} initialValues={{ remember: true }} onFinish={onFinish} onFinishFailed={onFinishFailed} autoComplete="off" {...layout} ref={formRef} > <Form.Item label="商品名稱" name="goods_name" rules={[{ required: true, message: '請輸入商品名稱' }]} > <Input /> </Form.Item> <Form.Item label="商品價格" name="goods_price" rules={[{ required: true, message: '請輸入商品價格' }]} > <Input /> </Form.Item> <Form.Item label="商品數(shù)量" name="goods_number" rules={[{ required: true, message: '請輸入商品數(shù)量' }]} > <Input /> </Form.Item> <Form.Item label="商品重量" name="goods_weight" rules={[{ required: true, message: '請輸入商品重量' }]} > <Input /> </Form.Item> <Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 16 }}> <Button type="primary" htmlType="submit"> Submit </Button> <Button type="primary" onClick={() => { (editHandleCancel()) }} danger> 取消 </Button> </Form.Item> </Form> </Modal>
刪除商品
點(diǎn)擊刪除按鈕傳遞一個id,然后請求刪除接口即可
// 刪除 const delGoods = async (e) => { console.log(e); let { meta } = await axios.delete(`goods/${e}`) switch (meta.status) { case 200: message.success(meta.msg) break; default: message.warning("刪除失敗") break; } getUserData() } <Button type="primary" size="small" danger onClick={() => { delGoods(record.goods_id) }} > <DeleteOutlined /> </Button>
完整代碼
import { DeleteOutlined, EditOutlined } from '@ant-design/icons'; import { Button, Card, Form, Input, message, Modal, Pagination, Table, Upload } from 'antd'; import React, { useEffect, useRef, useState } from 'react'; import axios from '../utils/request'; import './goods.scss'; const { Search } = Input; const props = { name: 'file', action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76', headers: { authorization: 'authorization-text', } } export default function Goods() { let formRef = useRef() let addFormRef = useRef(null) const [userData, setUserData] = useState([]) // 添加彈窗狀態(tài) const [addIsModalVisible, setAddIsModalVisible] = useState(false); // 存圖片 let [img,setimg] = useState(""); // 搜索 let [search, setSearch] = useState("") // 總條數(shù) let [total, setTotal] = useState(0) // 當(dāng)前頁 let [page, setPage] = useState(1) // 修改彈出框 const [isModalVisible, setIsModalVisible] = useState(false); // 每頁條數(shù) let [pageSize, setPageSize] = useState(2) const [goodid, setgoodid] = useState(0) const showModal = () => { setAddIsModalVisible(true); }; // 修改商品 const onFinish = async (values) => { let { meta } = await axios.put(`goods/${goodid}`, { goods_name: values.goods_name, goods_number: values.goods_number, goods_price: values.goods_price, goods_weight: values.goods_weight }) // console.log(data); if (meta.status === 200) { message.success(meta.msg) setIsModalVisible(false); getUserData() } else { message.info(meta.msg) setIsModalVisible(false); } }; const onFinishFailed = (errorInfo) => { console.log('Failed:', errorInfo); }; // 修改彈出框,數(shù)據(jù)回填 const showedit = async (e) => { setIsModalVisible(true); setgoodid(e) let { data } = await axios.get(`goods/${e}`) console.log(data); formRef.current.setFieldsValue({ goods_name: data.goods_name, goods_price: data.goods_price, goods_number: data.goods_number, goods_weight: data.goods_weight }) }; // 初始化數(shù)據(jù) useEffect(() => { getUserData() setPage(1) }, [search, page, pageSize]) // 添加 const layout = { labelCol: { span: 4 }, wrapperCol: { span: 20 } }; // 添加取消 const addHandleCancel = () => { setAddIsModalVisible(false); }; // 修改取消按鈕 const editHandleCancel = () => { setIsModalVisible(false) } // 刪除 const delGoods = async (e) => { console.log(e); let { meta } = await axios.delete(`goods/${e}`) switch (meta.status) { case 200: message.success(meta.msg) break; default: message.warning("刪除失敗") break; } getUserData() } // 初始化請求數(shù)據(jù) 用戶 const getUserData = async () => { console.log(pageSize); console.log(search); console.log(page); let { data } = await axios.get(`goods?pagenum=${page}&query=${search}&pagesize=${pageSize}`) console.log(data.goods); if (data) { setTotal(data.total); setUserData(data.goods); } } const columns = [ { title: '商品名稱', dataIndex: 'goods_name', key: 'username', }, { title: '商品價格', dataIndex: 'goods_price', key: 'email', }, { title: '商品重量', dataIndex: 'goods_weight', key: 'mobile', }, { title: '創(chuàng)建時間', dataIndex: 'goods_state', key: 'role_name', }, { title: '操作', key: 'action', render: (_, record) => { return ( <> <Button type="primary" size="small" onClick={() => { showedit(record.goods_id) }}> <EditOutlined /> </Button> <Button type="primary" size="small" danger onClick={() => { delGoods(record.goods_id) }} > <DeleteOutlined /> </Button> </> ) } } ]; // 搜索 const onSearch = (val) => { setSearch(val) } // 分頁 const onChange = (page, pageSize) => { setPage(page) setPageSize(pageSize) } let token = sessionStorage.getItem("token"); // 添加商品 const onAdd = async (value)=>{ console.log(value); let pics = [{pic:img}]; let data= await axios.post("goods",{...value,pics}) setAddIsModalVisible(false); getUserData() } const success = (info)=>{ if(info.file.status==="done"){ console.log(info.file.response.data.tmp_path); setimg(info.file.response.data.tmp_path) } } return ( <div className='goods'> {/* 主體表格區(qū)域 */} <Card > <Search allowClear placeholder="input search text" onSearch={onSearch} enterButton style={{ width: 300, height: 60 }} /> <Button type="primary" onClick={showModal}> <EditOutlined /> 添加商品 </Button> <Table pagination={false} bordered dataSource={userData} columns={columns} rowKey={(record) => record.goods_id} /> <Pagination className='pagination' total={total} showSizeChanger showQuickJumper pageSizeOptions={[10, 20, 30]} defaultPageSize={2} showTotal={(total) => `Total ${total} items`} onChange={onChange} /> </Card> <Modal title="商品添加" visible={addIsModalVisible} footer={null} ref={addFormRef}> <Form name="basic" labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} initialValues={{ remember: true }} onFinish={onAdd} onFinishFailed={onFinishFailed} autoComplete="off" > <Form.Item label="商品名稱" name="goods_name" rules={[{ required: true, message: '請輸入商品名稱' }]} > <Input /> </Form.Item> <Form.Item label="商品價格" name="goods_price" rules={[{ required: true, message: '請輸入商品價格' }]} > <Input /> </Form.Item> <Form.Item label="商品數(shù)量" name="goods_number" rules={[{ required: true, message: '請輸入商品數(shù)量' }]} > <Input /> </Form.Item> <Form.Item label="商品重量" name="goods_weight" rules={[{ required: true, message: '請輸入商品重量' }]} > <Input /> </Form.Item> <Form.Item label="商品圖片" name="pics" > <Upload {...props} action='http://api.xiaohuihui0728.cn:8888/api/private/v1/upload' headers={{"Authorization":token}} onChange={success} listType='picture'> <Button type='primary'>上傳圖片</Button> </Upload> </Form.Item> <Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 16 }}> <Button type="primary" htmlType="submit" > Submit </Button> <Button type="primary" onClick={() => { (addHandleCancel()) }} danger> 取消 </Button> </Form.Item> </Form> </Modal> {/* 修改彈出框 */} <Modal title="修改商品" visible={isModalVisible} footer={null}> <Form name="basic" labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} initialValues={{ remember: true }} onFinish={onFinish} onFinishFailed={onFinishFailed} autoComplete="off" {...layout} ref={formRef} > <Form.Item label="商品名稱" name="goods_name" rules={[{ required: true, message: '請輸入商品名稱' }]} > <Input /> </Form.Item> <Form.Item label="商品價格" name="goods_price" rules={[{ required: true, message: '請輸入商品價格' }]} > <Input /> </Form.Item> <Form.Item label="商品數(shù)量" name="goods_number" rules={[{ required: true, message: '請輸入商品數(shù)量' }]} > <Input /> </Form.Item> <Form.Item label="商品重量" name="goods_weight" rules={[{ required: true, message: '請輸入商品重量' }]} > <Input /> </Form.Item> <Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 16 }}> <Button type="primary" htmlType="submit"> Submit </Button> <Button type="primary" onClick={() => { (editHandleCancel()) }} danger> 取消 </Button> </Form.Item> </Form> </Modal> </div> ) }
到此這篇關(guān)于react電商商品列表的實(shí)現(xiàn)流程詳解的文章就介紹到這了,更多相關(guān)react商品列表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react-native滑動吸頂效果的實(shí)現(xiàn)過程
這篇文章主要給大家介紹了關(guān)于react-native滑動吸頂效果的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用react-native具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06React系列useSyncExternalStore學(xué)習(xí)詳解
這篇文章主要為大家介紹了React系列useSyncExternalStore的學(xué)習(xí)及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07React immer與Redux Toolkit使用教程詳解
這篇文章主要介紹了React中immer與Redux Toolkit的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10Native?Memory?Tracking追蹤區(qū)域示例分析
這篇文章主要為大家介紹了Native?Memory?Tracking追蹤區(qū)域示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11