react電商商品列表的實現(xiàn)流程詳解
整體頁面效果

項目技術(shù)點
- antd組件庫,@ant-design/icons antd的圖標庫
- 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} />添加商品
添加彈出對話框,添加里面有一個上傳圖片,我們上傳的圖片有一個單獨的添加接口,所以我們使用action屬性綁定我們要上傳的路徑,headres獲取token,使用onChange獲取圖片上傳的路徑,然后在我們點擊提交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)鍵字,然后在分頁中進行數(shù)據(jù)屬性的配置即可
// 搜索
let [search, setSearch] = useState("")
// 總條數(shù)
let [total, setTotal] = useState(0)
// 當前頁
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}
/>修改商品
我們在點擊修改彈出對話框的同時,需要把數(shù)據(jù)綁定到輸入框內(nèi),我們利用formRef.current.setFieldsValue進行數(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>刪除商品
點擊刪除按鈕傳遞一個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)
// 當前頁
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電商商品列表的實現(xiàn)流程詳解的文章就介紹到這了,更多相關(guān)react商品列表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React系列useSyncExternalStore學(xué)習(xí)詳解
這篇文章主要為大家介紹了React系列useSyncExternalStore的學(xué)習(xí)及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07
React immer與Redux Toolkit使用教程詳解
這篇文章主要介紹了React中immer與Redux Toolkit的使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10
Native?Memory?Tracking追蹤區(qū)域示例分析
這篇文章主要為大家介紹了Native?Memory?Tracking追蹤區(qū)域示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11

