如何优化React localStorage存储代码以实现DRY(避免重复)原则?
优化方案:遵循DRY原则重构你的React localStorage逻辑
嘿,我瞅了你的代码,确实有不少重复的localStorage操作逻辑,咱们一步步把它重构得更简洁、更易维护,完美贴合DRY原则~
核心重复点分析
你代码里的重复主要集中在这几块:
- 两次重复的
localStorage.getItem+JSON.parse操作(分别处理文本和URL) - 两次几乎一样的数组更新+存储逻辑(扩展运算符合并新值后存回localStorage)
- 两处重复的列表渲染
map逻辑
具体优化步骤
1. 抽象通用的localStorage工具函数
把重复的读取、更新逻辑封装成通用函数,这样不用每次都写重复的JSON解析和数组处理:
// 通用读取localStorage数组的函数 const getStoredArray = (storageKey) => { return JSON.parse(localStorage.getItem(storageKey) || "[]"); }; // 通用更新localStorage数组的函数 const updateStoredArray = (storageKey, newValue) => { const currentArray = getStoredArray(storageKey); const updatedArray = [...currentArray, newValue]; localStorage.setItem(storageKey, JSON.stringify(updatedArray)); return updatedArray; };
2. 用状态缓存localStorage数据,避免重复读取
原代码每次渲染都会重新读取localStorage,咱们用React的useState初始化时加载数据,后续更新时同步状态,减少不必要的IO操作:
const [localStoredValues, setLocalStoredValues] = useState(() => getStoredArray("localValue")); const [urlStoredValues, setUrlStoredValues] = useState(() => getStoredArray("URLValue"));
3. 简化按钮点击逻辑,复用工具函数
把原来重复的数组更新逻辑替换成调用通用函数,同时同步组件状态:
- Save按钮逻辑:
const saveBtn = () => { const updatedLocalArray = updateStoredArray("localValue", leadValue.inputVal); setLocalStoredValues(updatedLocalArray); setMyLeads(prev => [...prev, leadValue.inputVal]); setDisplay(false); };
- Tab捕获按钮逻辑:
const tabBtn = () => { chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { const url = tabs[0].url; const updatedUrlArray = updateStoredArray("URLValue", url); setUrlStoredValues(updatedUrlArray); setMyLeads(prev => [...prev, url]); }); setDisplay(false) };
4. 合并重复的列表渲染逻辑
原来的displayLocalItems和displayTabUrls可以合并成一个数组后统一渲染,减少重复的JSX代码:
const displayAllStoredItems = [...localStoredValues, ...urlStoredValues].map(item => ( <List key={item} val={item} /> ));
5. 完善删除按钮的状态同步
清空localStorage后,别忘了同步重置组件内的状态:
const deleteBtn = () => { window.localStorage.clear(); setMyLeads([]); setLocalStoredValues([]); setUrlStoredValues([]); };
完整优化后的代码
/*global chrome*/ import { useState } from 'react'; import List from './components/List' import { SaveBtn, DeleteBtn, DisplayBtn, TabBtn} from "./components/Buttons" // 通用localStorage操作工具函数 const getStoredArray = (storageKey) => { return JSON.parse(localStorage.getItem(storageKey) || "[]"); }; const updateStoredArray = (storageKey, newValue) => { const currentArray = getStoredArray(storageKey); const updatedArray = [...currentArray, newValue]; localStorage.setItem(storageKey, JSON.stringify(updatedArray)); return updatedArray; }; function App() { const [myLeads, setMyLeads] = useState([]); const [leadValue, setLeadValue] = useState({ inputVal: "", }); const [display, setDisplay] = useState(false); // 用状态缓存localStorage数据 const [localStoredValues, setLocalStoredValues] = useState(() => getStoredArray("localValue")); const [urlStoredValues, setUrlStoredValues] = useState(() => getStoredArray("URLValue")); const tabBtn = () => { chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) { const url = tabs[0].url; const updatedUrlArray = updateStoredArray("URLValue", url); setUrlStoredValues(updatedUrlArray); setMyLeads(prev => [...prev, url]); }); setDisplay(false) }; const handleChange = (event) => { const { name, value } = event.target; setLeadValue((prev) => ({ ...prev, [name]: value, })); }; const saveBtn = () => { const updatedLocalArray = updateStoredArray("localValue", leadValue.inputVal); setLocalStoredValues(updatedLocalArray); setMyLeads(prev => [...prev, leadValue.inputVal]); setDisplay(false); }; const displayBtn = () => { setDisplay(true); }; const deleteBtn = () => { window.localStorage.clear(); setMyLeads([]); setLocalStoredValues([]); setUrlStoredValues([]); }; const listItem = myLeads.map((led) => ( <List key={led} val={led} /> )); // 合并后的存储项渲染逻辑 const displayAllStoredItems = [...localStoredValues, ...urlStoredValues].map(item => ( <List key={item} val={item} /> )); return ( <main> <input name="inputVal" value={leadValue.inputVal} type="text" onChange={handleChange} required /> <SaveBtn saveBtn={saveBtn} /> <TabBtn tabBtn={tabBtn} /> <DisplayBtn displayBtn={displayBtn} /> <DeleteBtn deleteBtn={deleteBtn} /> <ul>{listItem}</ul> {display && ( <ul> {displayAllStoredItems} </ul> )} </main> ); } export default App;
额外优化建议(可选)
如果后续不需要区分手动输入和Tab捕获的内容,可以把两个localStorage键合并成一个(比如allLeads),这样能进一步减少逻辑复杂度,不过这取决于你的业务需求~
内容的提问来源于stack exchange,提问作者user3574939
相关产品推荐
相关产品推荐

