實習小記(個人中心的編輯模塊)

實習小記(個人中心的編輯模塊)

項目需要加一個個人中心的編輯模塊,也是差不多搞了一天下來,其中遇到了很多問題,也是來記錄、分享一下。

技術棧:React、antd、TypeScript

在這里插入圖片描述

需求
點擊編輯,彈出編輯個人信息浮窗,調用后端接口渲染初始表單。其中頭像是點擊上傳新頭像,手機號是不可修改。

代碼

import {Form,Modal,FormProps,Input,message,Avatar,Upload,Typography
} from 'antd'
import React, { useImperativeHandle, useState } from 'react'
import { UserOutlined } from '@ant-design/icons'
import { Users } from '@ysx-use/certificate-service'
import { useStateAsync } from '@ysx-use/hooks'
import { noop } from '@ysx-use/shared'
import { eventBus } from '@/components'
import { personalStore, logout } from '@/store'const { Text } = Typographyexport namespace PersonalModule {export interface FormModalInstance {show: (id?: number) => void}export interface FormModalProps {onSuccess?: () => void}export const FormModal = React.memo(React.forwardRef<FormModalInstance, FormModalProps>(({ onSuccess = noop }, ref) => {const [isModalOpen, setIsModalOpen] = useState(false)const [id, setId] = useState<number>()const [avatarUrl, setAvatarUrl] = useState<string>('') // 顯示頭像const [form] = Form.useForm<Users.Model>()useImperativeHandle(ref, () => ({show(id) {setId(id)form.resetFields()if (id) {Users.getMeInfo().then((res) => {const data = res.data || {}form.setFieldsValue({...data,password: undefined // 密碼不顯示})setAvatarUrl(data.avatar || '')})}setIsModalOpen(true)}}))const handleCancel = () => {setIsModalOpen(false)}const submit = useStateAsync(async (form: Users.Model) => {await Users.updatePersonalInfo({...form,password: form.password || undefined})personalStore.remove()message.success('修改成功,請重新登錄')eventBus.emit('PersonalReload', id)logout()},{ immediate: false })const onFinish: FormProps<Users.Model>['onFinish'] = (values) => {submit.execute(values)}const onFinishFailed: FormProps<Users.Model>['onFinishFailed'] = (errorInfo) => {console.error('Failed:', errorInfo)}const onSubmit = () => {form.submit()}// 上傳頭像邏輯const importAvatar = useStateAsync(async (file: File) => {const res = await Users.importPersonalAvatar(file)const url = res?.data || ''if (url) {setAvatarUrl(url)form.setFieldsValue({ avatar: url })message.success('頭像上傳成功')} else {message.error('上傳失敗,請重試')}},{immediate: false})return (<Modaltitle="編輯個人信息"open={isModalOpen}onCancel={handleCancel}onOk={onSubmit}closable><Formstyle={{ marginTop: 16 }}form={form}layout="vertical"name="personal-form"onFinish={onFinish}onFinishFailed={onFinishFailed}autoComplete="off"><Form.Item label="頭像" name="avatar"><div style={{ display: 'flex', alignItems: 'center', gap: 16 }}><Uploadaccept=""customRequest={() => {}}//beforeUpload={() => false} // 阻止默認上傳showUploadList={false}onChange={(info) => {if (info.file.originFileObj) {importAvatar.execute(info.file.originFileObj)}}}maxCount={1}disabled={importAvatar.isLoading}name="file"><Avatarsize={64}icon={<UserOutlined />}src={avatarUrl}style={{ cursor: 'pointer' }}/></Upload><Text type="secondary">點擊頭像上傳更換</Text></div></Form.Item><Form.Item<Users.Model>label="賬戶"name="username"rules={[{ required: true, message: '請輸入賬戶名' }]}><Input placeholder="請輸入賬戶名" /></Form.Item><Form.Item<Users.Model> label="手機號" name="mobile" extra="手機號一旦注冊不可修改"><Input readOnly /></Form.Item><Form.Item<Users.Model> label="昵稱" name="nickname"><Input placeholder="請輸入昵稱" /></Form.Item><Form.Item<Users.Model> label="密碼" name="password"><Input.Password placeholder="如需修改請輸入新密碼" /></Form.Item></Form></Modal>)}))
}
  • 個人中心頁(index.tsx) :用于展示用戶信息。

  • 編輯彈窗模塊(FormModal) :用于修改頭像、昵稱、密碼等信息。

個人中心主頁面

實現:

使用了antd pro(中后臺管理)的組件PageContainer, ProCard, ProDescriptions

從狀態管理中獲取當前登錄用戶信息

通過 useRef 持有對彈窗組件的引用,以便調用 show(user_id) 彈出表單。

掛載
<PersonalModule.FormModal ref={formModal}></PersonalModule.FormModal>

點擊編輯按鈕時,調用 FormModal 暴露的 show 方法,打開彈窗。

通過 ProDescriptions 來渲染個人信息

個人中心的編輯彈窗

功能:

  • 支持修改昵稱、密碼、頭像。

  • 上傳頭像后立即預覽。

  • 保存后強制重新登錄。

實現:

通過 useImperativeHandle 實現組件間命令式通信

useImperativeHandle(ref, () => ({show(id) {// 重置表單、加載用戶數據}
}))

其中調用了獲取用戶信息接口去加載當前用戶信息并填充到編輯表單中

頭像上傳
使用封裝的 useStateAsync 來處理異步上傳邏輯,增強可控性與狀態追蹤。
通過點擊 Avatar,用戶可直接上傳圖片替換頭像,體驗更友好。

更新個人信息后,清空用戶狀態并觸發登出,強制用戶重新登錄以刷新身份數據。

然后遇到了很多問題

手機號不可修改

加下面注釋

<Form.Item<Users.Model> label="手機號" name="mobile" extra="手機號一旦注冊不可修改"><Input ></Input>{/* <div style={{ color: '  #C0C0C0', fontSize: '12px' }}>手機號一旦注冊不可修改</div> */}
</Form.Item>

起初是直接給Input加了一個disabled
發現不行,不會被渲染初始值
因為:
Ant Design 的 Form.Item + Input disabled 組合有個限制:
被 disabled 的 Input 不會響應 setFieldsValue 的值變化,AntD 默認不更新它(這在受控組件中屬于正常行為)。

改成了 readOnly

還有一個問題:<Form.Item> 內的 div 干擾了渲染

Ant Design 的 <Form.Item> 不支持你在其中直接放多個非表單組件子元素(如 <Input /> 之外的 <div>)。

這種用法會導致:

  • 表單字段渲染混亂(尤其是 setFieldsValue 失效或渲染錯位);
  • 特別是你用的 form 是受控的,value 綁定會丟失。

可以使用 Form.Item 的 extra 屬性,會在下方顯示提示信息,渲染安全,不會干擾 Input

頭像上傳

首先這是又用了一個獨立的接口,然后在Axios實例的請求攔截器那里要進行配置,在請求真正發出前對 config 進行處理。

instance.interceptors.request.use((config) => {// console.log(config)const { url } = configif (url && !whiteList.includes(url)) {const auth = accessStore.get().access_tokenif (auth) {config.headers.Authorization = `Bearer ${auth}`}} else {config.headers.Authorization = ''}if (url === Users.ApiUrls.ExportTemplate) {config.responseType = 'blob'config.headers['Content-Type'] = 'application/vnd.ms-csv'}if (url === Users.ApiUrls.ImportData|| url===Users.ApiUrls.ImportPersonalAvatar) {const formData = new FormData()formData.append('file', config.data.file)config.data = formDataconfig.headers['Content-Type'] = 'multipart/form-data'}return config},(error) => {return Promise.reject(error)}
)
  1. 鑒權處理:請求 URL 存在并且不在 whiteList 白名單中,請求頭加 token

  2. 文件下載:設置響應類型與內容類型

  3. 文件上傳:封裝為 FormData

  4. 錯誤處理

組件的默認行為

完成后,發現了一個不知道哪里發出的 POST http://localhost:3000/personal 請求
發現了這個url是對應的個人中心頁面,但應該是 GET 方法
所以應該是某個組件或 hook 在加載 /personal 頁面時自動觸發了一個不必要的 POST 請求。
然后發現是頭像上傳組件的 問題

<Form.Item label="頭像" name="avatar"><div style={{ display: 'flex', alignItems: 'center', gap: 16 }}><Uploadaccept=""customRequest={() => {}}//beforeUpload={() => false} // 阻止默認上傳showUploadList={false}onChange={(info) => {if (info.file.originFileObj) {importAvatar.execute(info.file.originFileObj)}}}maxCount={1}disabled={importAvatar.isLoading}name="file"><Avatarsize={64}icon={<UserOutlined />}src={avatarUrl}style={{ cursor: 'pointer' }}/></Upload><Text type="secondary">點擊頭像上傳更換</Text></div>
</Form.Item>

如果 info.file.originFileObj 不存在,Upload 組件會默認走 action=“/personal” 來上傳!
你沒有顯式指定 action 參數,所以 Ant Design 的 組件默認會使用當前頁面地址 /personal 作為上傳地址。

使用beforeUpload={() => false} // 阻止默認上傳
加這個就不能上傳本地圖片了(都沒有發起網絡請求)

? 阻止 Ant Design Upload 組件的 自動上傳行為

? 但不會觸發 onChange 中的 info.file.originFileObj → 因為根本沒觸發上傳流程

最后用customRequest={() => {}}
會觸發onChange,適合手動上傳

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/91106.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/91106.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/91106.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【7】串口編程三種模式(查詢/中斷/DMA)韋東山老師學習筆記(課程聽不懂的話試著來看看我的學習筆記吧)

<1>前置概念補充在深入拆解三種模式前&#xff0c;先通過提供的 “函數對比表” 建立整體認知&#xff1a;這張表是串口收發的「武器庫索引」&#xff0c;清晰標注了查詢、中斷、DMA 三種模式下&#xff0c;收發 / 回調函數的對應關系。后續會結合實際代碼&#xff0c;講…

【Kubernetes 指南】基礎入門——Kubernetes 201(二)

二、滾動升級- 滾動升級&#xff08;Rolling Update&#xff09;通過逐個容器替代升級的方式來實現無中斷的服務升級&#xff1a;- 在滾動升級的過程中&#xff0c;如果發現了失敗或者配置錯誤&#xff0c;還可以隨時回滾&#xff1a;- 需要注意的是&#xff0c; kubectl rolli…

網絡資源模板--基于Android Studio 實現的圖書商城App

目錄 一、測試環境說明 二、項目簡介 三、項目演示 四、部設計詳情&#xff08;部分) 登錄注冊頁 首頁 五、項目源碼 一、測試環境說明 電腦環境 Windows 11 編寫語言 JAVA 開發軟件 Android Studio (2020) 開發軟件只要大于等于測試版本即可(近幾年官網直接下載…

JavaWeb 進階:Vue.js 與 Spring Boot 全棧開發實戰(Java 開發者視角)

作為一名 Java 開發工程師&#xff0c;當你掌握了 HTML、CSS 和 JavaScript 的基礎后&#xff0c;是時候接觸現代前端框架了。Vue.js 以其簡潔的 API、漸進式的設計和優秀的中文文檔&#xff0c;成為眾多 Java 開發者入門前端框架的首選。Vue.js 讓你能快速構建響應式、組件化的…

智能體產品化的關鍵突破:企業智能化轉型的“最后一公里”如何邁過?

智能體產品化的關鍵突破&#xff1a;企業智能化轉型的“最后一公里”如何邁過&#xff1f; 在人工智能迅猛發展的當下&#xff0c;智能體&#xff08;Agent&#xff09;成為企業數字化轉型的新引擎。無論是市場分析、客戶服務&#xff0c;還是自動化辦公&#xff0c;智能體都被…

Rust × Elasticsearch官方 `elasticsearch` crate 上手指南

1 為什么選擇官方 Rust 客戶端&#xff1f; 語義化兼容&#xff1a;客戶端 主版本 與 ES 主版本 嚴格對應&#xff0c;8.x 客戶端可對接任何 8.x 服務器&#xff1b;不存在跨主版本兼容承諾 (docs.rs)100% API 覆蓋&#xff1a;穩定 API 全量映射&#xff0c;Beta/實驗特性可按…

怎樣畫流程圖?符號與流程解構教程

在數字化辦公和項目管理日益復雜的當下&#xff0c;流程圖早已不是工程師、項目經理的專屬工具&#xff0c;它正快速成為每一位職場人提升表達效率、理清工作邏輯的利器。無論是軟件開發中的流程規范、產品設計階段的用戶路徑&#xff0c;還是企業內部的審批流程、團隊協作機制…

vue3 + vite || Vue3 + Webpack創建項目

1.vue3 vite搭建項目方法 &#xff08;需要提前裝node,js&#xff09; 1. 使用官方 create-vite 工具&#xff08;推薦&#xff09; 1.使用npm----------------------------- npm create vuelatest2.使用pnpm----------------------------- pnpm create vuelatest3.使用yarn--…

Vue2-封裝一個含所有表單控件且支持動態增減行列的表格組件

效果1. 無編輯權限&#xff1a;顯示普通表格2. 有編輯權限&#xff1a;根據配置顯示編輯控件3. 可以動態新增行&#xff0c;也可以動態新增列 核心代碼無權限情況的核心代碼<!-- 無編輯權限時顯示普通表格 --><el-tablev-if"!hasEditPermission"ref"ta…

網絡原理 - TCP/IP(一)

目錄 1. 應用層&#xff1a;用戶與網絡的 “交互窗口” 1.1 應用層協議&#xff1a;規范交互的 “通用語言” 1.2 自定義協議&#xff1a;適配特殊需求的 “專屬規則” 1.3 應用層數據格式&#xff1a;讓數據 “說得明白” 1.3.1 XML&#xff1a;結構化但繁瑣的 “老…

Orange的運維學習日記--16.Linux時間管理

Orange的運維學習日記–16. Linux時間管理 文章目錄Orange的運維學習日記--16. Linux時間管理系統與硬件時鐘時鐘類型對比查看內核支持的時鐘源本地時間調整使用 date 查看與設置一次性同步&#xff1a;ntpdate同步到硬件時鐘&#xff1a;hwclock基于 systemd 的 timedatectl交…

Git 與 GitHub 的對比與使用指南

Git 與 GitHub 的對比與使用指南 在軟件開發中&#xff0c;Git 和 GitHub 是兩個密切相關但本質不同的工具。下面我將逐步解釋它們的定義、區別、核心概念以及如何協同使用&#xff0c;確保內容真實可靠&#xff0c;基于廣泛的技術實踐。 1. 什么是 Git&#xff1f; Git 是一個…

20250726-4-Kubernetes 網絡-Service DNS名稱解析_筆記

一、Service DNS名稱 ?1. 例題:通信需求 通信場景:項目A中的Pod需要與項目B中的Pod進行通信,直接使用Pod IP不可行,因為Pod IP會隨著Pod生命周期變化。 解決方案:通過Service提供的穩定IP地址進行通信,不受Pod重建、擴容/縮容等操作影響。 2. CoreDNS介紹 ?? 基本功能…

vscode 登錄ssh記住密碼直接登錄設置

第一種情況在系統已經生成密鑰對的情況下&#xff1a;點擊這里的設置第二步&#xff1a;第三步&#xff1a;沒有填寫的給填寫一下第四步驟&#xff1a;保存后進入選擇這個點開第五步&#xff1a;去Linux終端下輸入這個命令就OK了echo "ssh-rsa內容" >> ~/.ssh/…

Nginx 動靜分離配置(詳細版)

本文介紹了Nginx 動靜分離相關配置&#xff0c;主要包括了配置文件創建、配置示例、配置原理解析以及重新啟用配置文件等等 本文目錄1. 創建 Nginx 配置文件2. 配置示例3. 配置原理解析4. 啟用配置文件并重新加載 Nginx1. 創建 Nginx 配置文件 在 /etc/nginx/sites-available …

C# CAN通信上位機系統設計與實現

C# CAN通信上位機系統設計與實現 C# CAN通信上位機程序&#xff0c;支持多種CAN適配器&#xff0c;提供數據收發、協議解析、數據可視化等功能。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; usi…

Ubuntu20.04子系統

常用 # 導出分發版到 E盤 wsl --export Ubuntu-20.04 E:\wsl-ubuntu20.04.tar # 注銷原有分發版 wsl --unregister Ubuntu-20.04 # 導入到 E盤的新路徑&#xff08;例如 E:\WSL\Ubuntu-20.04&#xff09; wsl --import Ubuntu-20.04 E:\WSL\Ubuntu-20.04 E:\wsl-ubuntu20.04.t…

【設計模式】狀態模式 (狀態對象(Objects for States))

狀態模式&#xff08;State Pattern&#xff09;詳解一、狀態模式簡介 狀態模式&#xff08;State Pattern&#xff09; 是一種 行為型設計模式(對象行為型模式)&#xff0c;它允許一個對象在其內部狀態改變時改變其行為。換句話說&#xff0c;對象看起來好像修改了它的類。 你…

工業前端組件庫重構心法:如何讓開發效率提升60%的交互模塊設計邏輯

工業前端組件庫重構心法&#xff1a;如何讓開發效率提升60%的交互模塊設計邏輯內容摘要在工業項目開發中&#xff0c;前端組件庫是提升開發效率的關鍵。然而&#xff0c;許多團隊的組件庫存在設計不合理、維護困難等問題&#xff0c;導致開發效率低下。如果能夠重構組件庫&…

leetcode 74. 搜索二維矩陣

二分查找經典題目&#xff1b;根據矩陣的特點&#xff0c;不需要把矩陣拉成一維&#xff0c;二維轉成一維映射關系為a[i]matrix[?i//n?][i%n]&#xff1b;然后開始二分查找&#xff0c;一直二分的收縮區間&#xff1b;class Solution:def searchMatrix(self, matrix: List[Li…