Jinyang's Blog
website·Indexed 30 days ago
https://jinyang79.github.io/A collection of front-end development records and shares by Jinyang, covering topics such as React, Redux Toolkit, Vite migration, Ant Design 4.x upgrades, SignalR, SheetJS, and low-code platform practices.
What's inside Jinyang's Blog
- The Low-code H5 Activity Page Platform is a visual drag-and-drop development environment designed specifically for building H5 activity pages. It allows developers to quickly construct pages and generate standalone HTML files for direct use, while still supporting secondary development to handle complex business logic. The platform is built with Vue and supports multiple targets including H5, Apps, and Mini-programs.
Reduce repetitive state updates using addMatcher in Redux Toolkit
When multiple async thunks share the same state transitions (e.g., setting
loading = trueon any pending action), usebuilder.addMatcherinstead of repeatingbuilder.addCasefor every action.addMatchertakes a predicate function that returns a boolean. If the function returns true for a given action, the reducer logic is executed.Critical Constraint: All
builder.addMatchercalls must be placed after allbuilder.addCasecalls in theextraReducersbuilder.import { AnyAction, createSlice } from '@reduxjs/toolkit'; // 1. Define matcher functions to identify action phases export const isPendingAction = (action: AnyAction) => action.type.endsWith('/pending'); export const isFulfilledAction = (action: AnyAction) => action.type.endsWith('/fulfilled'); export const isRejectedAction = (action: AnyAction) => action.type.endsWith('/rejected'); export const todosSlice = createSlice({ name: 'todos', initialState, reducers: {}, extraReducers: (builder) => { // Handle specific success logic first builder .addCase(getTodoList.fulfilled, (state, action) => { /* success logic */ }) .addCase(postTodoItem.fulfilled, (state, action) => { /* success logic */ }); // Use matchers for shared loading states at the end builder .addMatcher(isPendingAction, (state) => { state.loading = true; }) .addMatcher( (action) => isFulfilledAction(action) || isRejectedAction(action), (state) => { state.loading = false; } ); }, });Wake a Mac remotely using the Find My app
To wake a Mac that is in 'Sleep + Wi-Fi' mode with a remote control app (e.g., ToDesk) running in the background, you can use the Apple 'Find My' app on an iPhone. Opening the 'Find My' app and waiting for the device status to refresh to 'Location: Now' triggers the Mac to wake, allowing the remote control software to appear online and be accessible.1. Open 'Find My' app on iPhone -> Wait for status to update to 'Location: Now'. 2. Open ToDesk (or similar remote app) -> Connect to the now-online Mac.Import XLSX files to JSON using SheetJS
To import an Excel file, use theFileReaderAPI to read the file as a binary string. Then, useXLSX.readto parse the workbook andXLSX.utils.sheet_to_jsonto convert each sheet's content into a JavaScript object array where the Excel headers serve as the keys.import XLSX from 'xlsx'; import { message } from 'antd'; interface XlsxToJsonProps { file: File; onSuccess: (data: Record<string, string>[]) => void; } export function xlsxToJson({ file, onSuccess }: XlsxToJsonProps): void { let data: Record<string, string>[] = []; const fileReader = new FileReader(); fileReader.readAsBinaryString(file); fileReader.onload = (event: ProgressEvent<FileReader>) => { try { const result = event.target?.result; const workbook = XLSX.read(result, { type: 'binary' }); for (const sheet in workbook.Sheets) { if (Object.prototype.hasOwnProperty.call(workbook.Sheets, sheet)) { data = data.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet])); } } onSuccess(data); } catch (error) { message.error(`Import failed: ${error}`); } }; }Migrate Legacy Icons to Ant Design v4 Icons
The upgrade tool converts<Icon type={type} />to<LegacyIcon type={type} />from@ant-design/compatible. This causes the entire SVG icon library to be bundled, significantly increasing bundle size. To optimize, manually migrate to the new按需 (on-demand) import method using@ant-design/icons.// AVOID THIS (increases bundle size) import { Icon as LegacyIcon } from '@ant-design/compatible'; <LegacyIcon type="laptop" /> // DO THIS (on-demand import) import { LaptopOutlined } from '@ant-design/icons'; <LaptopOutlined />Export JSON data to XLSX using SheetJS
To export JSON data to an Excel file, use a mapping array to translate technical JSON keys into human-readable table headers. The process involves converting the JSON array into a worksheet usingXLSX.utils.json_to_sheet, creating a new workbook, and triggering a file download viaXLSX.writeFile.import { message } from 'antd'; import XLSX from 'xlsx'; interface JsonToXlsxProps { res: Record<string, any>[]; // API response data fileName: string; // Filename and sheet name mapKeyToHeader: [string, string][]; // Mapping of [jsonKey, headerName] } export function jsonToXlsx({ res, fileName, mapKeyToHeader }: JsonToXlsxProps): void { const headerMap = new Map<string, string>(mapKeyToHeader); const exportData = res.map((item) => { const dataItem: Record<string, string> = {}; headerMap.forEach((value, key) => { dataItem[value] = item[key]; }); return dataItem; }); try { const worksheet = XLSX.utils.json_to_sheet(exportData); const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, worksheet, fileName); XLSX.writeFile(workbook, `${fileName}.xlsx`); } catch (error) { message.error(`Export failed: ${error}`); } } // Usage Example: jsonToXlsx({ res: result, fileName: 'EmployeeInfo', mapKeyToHeader: [ ['name', 'Name'], ['age', 'Age'], ['address', 'Address'], ], });Apply JavaScript variable and function naming conventions
Follow these naming rules to improve code readability and maintainability:
- Avoid abbreviations: Do not shorten words unless they are industry-standard (e.g., avoid
assforAssociationorsbforStringBuilder). - Variables: Use nouns or noun phrases (e.g.,
value,options,fileText,columnName). - Booleans:
- Use
is...for "is it..." - Use
has...for "does it have..." - Use
can...for "can it..." - Use
...ablefor "is it able to..."
- Use
- Functions: Use a verb-object pattern (e.g.,
getUserInfo,insertRows,clearValue). - Avoid generic/temporary names: Do not use
_prefixes,temp, ormy. Every variable should have a meaningful name. - Be specific: Avoid vague names like
infoorcount; useuserInfoorclickCountinstead.
- Avoid abbreviations: Do not shorten words unless they are industry-standard (e.g., avoid
Handle environment variables in Vite
Vite does not useprocess.env. Instead, use theimport.meta.envobject. Only variables prefixed withVITE_are exposed to the client-side code to prevent leaking sensitive information.// Replace this: // const env = process.env.REACT_APP_BUILD_ENV // With this: const env = import.meta.env.VITE_APP_ENV// package.json "scripts": { "start": "cross-env VITE_APP_ENV=local vite" }Migrate a React project from Webpack to Vite
To migrate a React project from Webpack to Vite, follow these steps:
- Remove Webpack artifacts: Delete the
configandscriptsdirectories (if the project was ejected) and uninstall all webpack-related dependencies (e.g.,webpack,xxx-loader,xxx-webpack-plugin,babel-xxx,postcss-xxx). - Install Vite: Add
viteand@vitejs/plugin-react-refreshas devDependencies. - Configure Vite: Create a
vite.config.jsfile and set up the React refresh plugin. - Update package.json: Update scripts to use
vitefor starting, building, and previewing. - Relocate index.html: Move
public/index.htmlto the project root. Update the HTML to include a module script pointing to your entry point (e.g.,/src/index.jsx). Move other static assets tosrc/assets/and remove thepublicdirectory. - Start the server: Run the start script to begin the development server.
yarn add vite @vitejs/plugin-react-refresh -D// vite.config.js import { defineConfig } from "vite"; import reactRefresh from "@vitejs/plugin-react-refresh"; export default defineConfig({ plugins: [ reactRefresh(), ], });// package.json { "scripts": { "start": "vite", "build": "vite build", "preview": "vite preview" } }<!-- index.html --> <!DOCTYPE html> <html lang="zh-CN"> <body> <div id="root"></div> <script type="module" src="/src/index.jsx"></script> </body> </html>- Remove Webpack artifacts: Delete the
Pass function arguments as objects for better scalability
When a function requires more than two parameters, pass them as a single object instead of a parameter list. This improves readability, makes the order of arguments irrelevant, and simplifies the handling of optional parameters.// Avoid long parameter lists // function getUserInfo(name, age, sex, Address, phone) { ... } // Use an object for arguments function getUserInfo(args) { const { name, age, sex, Address, phone } = args; // ... } getUserInfo({ phone: '1388888', sex: 'male', age: 10, name: 'John', });Simplify conditional checks using logical operators and arrays
You can reduce the verbosity of your code by using logical AND (&&) for simple conditional execution andArray.prototype.includes()for checking a value against multiple possibilities.// Use && instead of if // if (a > 10) { doSomething(a); } a > 10 && doSomething(a); // Use .includes() instead of multiple OR checks // if (a === undefined || a === 10 || a === 15 || a === null) if ([undefined, 10, 15, null].includes(a)) { // ... }Automate Ant Design v3 to v4 upgrade using codemod
Use the official@ant-design/codemod-v4CLI tool to automatically migrate your project to Ant Design v4. The tool handles dependency updates and basic code transformations.# Run directly via npx npx -p @ant-design/codemod-v4 antd4-codemod src # OR install globally and run npm i -g @ant-design/codemod-v4 # or yarn global add @ant-design/codemod-v4 antd4-codemod src