15 مورد برتر در مورد اشتباهات استفاده مجدد هر برنامه نویس باید بدانند

هوک Usestate یکی از متداول ترین قلاب در React است ، اما چند اشتباه ظریف وجود دارد که توسعه دهندگان اغلب مرتکب می شوند.
در این مقاله ، شما یاد خواهید گرفت که چگونه از آنها جلوگیری کنید و منطق حالت بهتری بنویسید.
اشتباه 1: فرض کنید که به روزرسانی های SetState بلافاصله وضعیت
عملکرد SetState React ناهمزمان است ، به این معنی که دولت بلافاصله به روز نمی شود. اگر سعی می کنید بلافاصله پس از تماس با SetState از حالت به روز شده استفاده کنید ، باز هم مقدار قدیمی را دریافت خواهید کرد.
const [count, setCount] = useState(0);
function increment() {
setCount(count + 1);
setCount(count + 1); // count is still 0 and not incremented to 1
}
راه حل: از فرم به روزرسانی عملکردی استفاده کنید
وقتی حالت جدید به حالت قبلی بستگی دارد ، از فرم عملکردی استفاده کنید setState
بشر
function increment() {
setCount(prevCount => prevCount + 1);
setCount(prevCount => prevCount + 1); // Always works reliably
}
اشتباه 2: استفاده از اشیاء بدون حالت ادغام
هنگام کار با اشیاء در useState
، React به طور خودکار حالت جدید را با حالت قدیمی مانند ادغام نمی کند this.setState
در اجزای کلاس انجام می شود. در مؤلفه های کاربردی ، شما باید به صورت دستی شی را ادغام کنید.
const [user, setUser] = useState({ name: 'John', age: 30 });
function updateAge() {
setUser({ age: 31 }); // Overwrites the entire user state, removing `name`
}
راه حل: حالت قبلی را پخش کنید
همیشه حالت قبلی را برای حفظ خواص موجود گسترش دهید.
function updateAge() {
setUser(prevUser => ({ ...prevUser, age: 31 })); // Keeps `name` intact
}
اشتباه 3: با استفاده از حالت بی نظیر در دستگیرندگان رویداد
اگر کنترل کننده رویداد شما به وضعیت فعلی (به عنوان مثال ، داخل یک حلقه یا عملکرد Async) متکی است ، ممکن است به طور تصادفی از مقادیر حالت بی نظیر استفاده کنید.
const [count, setCount] = useState(0);
function handleClick() {
setTimeout(() => {
setCount(count + 1); // Uses the stale `count` value
}, 1000);
}
راه حل: از فرم به روزرسانی عملکردی استفاده کنید
برای اطمینان از اینکه همیشه آخرین حالت را دارید ، از فرم به روزرسانی عملکردی استفاده کنید.
function handleClick() {
setTimeout(() => {
setCount(prevCount => prevCount + 1); // Always gets the latest value
}, 1000);
}
اشتباه 4: استفاده از حالت مشتق شده در مؤلفه
به جای ذخیره مقادیر مشتق شده (مانند خواص محاسبه شده) در حالت ، آنها را در پرواز محاسبه کنید. این باعث می شود مجدداً غیر ضروری کاهش یابد و منطق حالت شما را ساده نگه می دارد.
const [firstName, setFirstName] = useState('John');
const [lastName, setLastName] = useState('Doe');
const [fullName, setFullName] = useState(`${firstName} ${lastName}`); // Derived state
function updateFirstName(name) {
setFirstName(name);
setFullName(`${name} ${lastName}`); // Extra work to keep `fullName` in sync
}
راه حل: مقادیر مشتق شده را مستقیماً محاسبه کنید
const [firstName, setFirstName] = useState('John');
const [lastName, setLastName] = useState('Doe');
// Calculate fullName dynamically
const fullName = `${firstName} ${lastName}`;
اشتباه 5: عدم استفاده از اولیه سازی تنبل برای محاسبات گران قیمت دولت
اگر حالت اولیه شما شامل یک محاسبات گران است (به عنوان مثال ، واکشی داده ها ، تجزیه JSON یا مقادیر محاسبه) ، می توانید از یک استفاده کنید عمل برای اولیه کردن دولت با تنبلی. این تضمین می کند که محاسبه فقط یک بار اتفاق می افتد و عملکرد را بهبود می بخشد.
const [data, setData] = useState(expensiveComputation()); // Runs every re-render of component
راه حل: از اولیه سازی تنبل استفاده کنید
const [data, setData] = useState(() => expensiveComputation()); // Runs only once first time component is rendered
این امر به ویژه در هنگام برخورد با مجموعه داده های بزرگ یا منطق پیچیده در هنگام اولیه سازی مفید است.
اشتباه 6: تنظیم مجدد دستی هر ایالت برای تنظیم مجدد کامل
هنگام جابجایی بین مؤلفه ها یا فرم های تنظیم مجدد ، ممکن است بخواهید حالت را به مقدار اولیه آن تنظیم کنید.
به جای تنظیم مجدد دستی هر قطعه از حالت ، می توانید از یک پیشخدمت کلیدی برای مجبور کردن واکنش به نابودی و بازپرداخت مؤلفه.
const [inputValue, setInputValue] = useState('');
function resetForm() {
setInputValue(''); // Manually reset each piece of state
}
راه حل: تنظیم مجدد خودکار با key
با تغییر key
Prop ، React مؤلفه را از بین می برد و مجدداً مجدداً تنظیم می کند و به طور خودکار تمام حالت را دوباره تنظیم می کند.
هر وقت مقدار متفاوتی را برای آن عبور می دهید key
برای یک مؤلفه ، مؤلفه دوباره ایجاد می شود.
function App() {
const [formKey, setFormKey] = useState(0);
function resetForm() {
setFormKey(prevKey => prevKey + 1); // Forces a reset
}
return (
<div>
<MyForm key={formKey} />
<button onClick={resetForm}>Reset Form</button>
</div>
);
}
اشتباه 7: عدم استفاده از آرایه ها یا اشیاء برای حالت مرتبط
به جای ایجاد چندین useState
قلاب برای قطعات مربوط به حالت ، آنها را به یک شیء یا آرایه واحد گروه بندی کنید. این باعث می شود کد شما سازمان یافته تر و مدیریت آن آسان تر شود.
const [x, setX] = useState(0);
const [y, setY] = useState(0);
function updateCoordinates(newX, newY) {
setX(newX);
setY(newY);
}
راه حل: با استفاده از حالت ترکیبی
const [coordinates, setCoordinates] = useState({ x: 0, y: 0 });
function updateCoordinates(newX, newY) {
setCoordinates({ x: newX, y: newY });
}
اشتباه 8: عدم استفاده از قلاب کاربر برای منطق پیچیده
برای انتقال حالت پیچیده (به عنوان مثال ، چندین حالت مرتبط یا به روزرسانی های مشروط) ، ترکیب را در نظر بگیرید useState
با useReducer
بشر این رویکرد ترکیبی کد شما را مدولار و قابل خواندن نگه می دارد.
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
async function fetchData() {
setLoading(true);
try {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
راه حل: استفاده کنید useReducer
برای حالت پیچیده
const initialState = { loading: false, error: null, data: null };
function reducer(state, action) {
switch (action.type) {
case 'FETCH_START':
return { ...state, loading: true, error: null };
case 'FETCH_SUCCESS':
return { ...state, loading: false, data: action.payload };
case 'FETCH_ERROR':
return { ...state, loading: false, error: action.payload };
default:
return state;
}
}
function MyComponent() {
const [state, dispatch] = useReducer(reducer, initialState);
async function fetchData() {
dispatch({ type: 'FETCH_START' });
try {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
dispatch({ type: 'FETCH_SUCCESS', payload: result });
} catch (err) {
dispatch({ type: 'FETCH_ERROR', payload: err.message });
}
}
return (
<div>
{state.loading && <p>Loading...</p>}
{state.error && <p>Error: {state.error}</p>}
{state.data && <pre>{JSON.stringify(state.data, null, 2)}</pre>}
</div>
);
}
این رویکرد منطق دولت را متمرکز می کند و مدیریت انتقال پیچیده را آسان تر می کند.
اشتباه 9: عدم استفاده از قلاب سفارشی برای تعامل با داده های محلی
با همگام سازی آن با ذخیره محلی ، حالت بارگذاری مجدد در صفحه را ادامه دهید. استفاده کردن useState
در ترکیب با useEffect
برای دستیابی به این یکپارچه در قلاب سفارشی.
const [theme, setTheme] = useState('light');
function toggleTheme() {
const newTheme = theme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
localStorage.setItem('theme', newTheme);
}
راه حل: همگام سازی ذخیره سازی محلی
حالت همگام سازی را با ذخیره محلی همگام سازی کنید.
const useLocalStorage = (key, initialValue) => {
const [value, setValue] = useState(() => {
try {
const localValue = window.localStorage.getItem(key);
return localValue ? JSON.parse(localValue) : initialValue;
} catch (error) {
return initialValue;
}
});
useEffect(() => {
window.localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
};
function App() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
function toggleTheme() {
setTheme(theme === 'light' ? 'dark' : 'light');
}
return (
<div>
<p>Current Theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}
این رویکرد تضمین می کند که دولت شما بدون مداخله دستی در جلسات ادامه می یابد.
یاد بگیرید که با استفاده از این رویکرد برنامه مدیریت کتاب را بسازید
اشتباه 10: بازنویسی داده های حالت با استفاده از ورودی های کنترل شده
هنگام مدیریت ورودی های کنترل شده (به عنوان مثال ، فرم ها) ، با استفاده از صحیح استفاده از ورودی کاربر خودداری کنید onChange
رویداد
const [formData, setFormData] = useState({ name: '', email: '' });
function handleChange(event) {
setFormData({ [event.target.name]: event.target.value }); // Overwrites other fields
}
همیشه مقادیر موجود را برای حفظ زمینه های دیگر پخش کنید.
راه حل: مقادیر موجود را پخش کنید
function handleChange(event) {
const { name, value } = event.target;
setFormData(prevData => ({ ...prevData, [name]: value })); // Preserves other fields
}
این تضمین می کند که تمام زمینه های موجود در فرم در حالی که فقط مورد مربوطه را به روز می کنند ، دست نخورده باقی می مانند.
اشتباه 11: عدم انجام چک های برابری در هنگام بروزرسانی دولت
React به طور خودکار بررسی نمی کند که آیا حالت جدید قبل از ایجاد یک رندر دوباره با حالت قدیمی متفاوت است یا خیر. برای جلوگیری از به روزرسانی های غیر ضروری ، به طور دستی مقدار جدید را با وضعیت فعلی مقایسه کنید.
const [count, setCount] = useState(0);
function updateCount(newCount) {
setCount(newCount); // Triggers a re-render even if `newCount === count`
}
راه حل: یک بررسی برابری اضافه کنید
function updateCount(newCount) {
if (newCount !== count) {
setCount(newCount); // Only updates state if the value changes
}
}
این امر مانع از تولید مجدد مجدد و بهبود عملکرد می شود.
اشتباه 12: همیشه از Redux یا زمینه برای ذخیره داده ها استفاده کنید
برای حالت های UI موقت (به عنوان مثال ، نشان دادن/پنهان کردن ماژال ها ، کشویی در حال جابجایی) ، استفاده کنید useState
به جای مدیریت این حالتها در سطح جهان (به عنوان مثال ، در ردوکس یا متن). این باعث می شود حالت جهانی شما تمیز و متمرکز بر داده های گسترده برنامه باشد.
// Storing modal visibility in Redux or Context is Not good
dispatch({ type: 'SET_MODAL_VISIBLE', payload: true });
راه حل: از دولت محلی استفاده کنید
const [isModalOpen, setIsModalOpen] = useState(false);
function openModal() {
setIsModalOpen(true);
}
function closeModal() {
setIsModalOpen(false);
}
return (
<div>
<button onClick={openModal}>Open Modal</button>
{isModalOpen && <Modal onClose={closeModal} />}
</div>
);
اشتباه 13: عدم استفاده از نحو عملکرد Updater برای عملیات Async
هنگام به روزرسانی حالت بر اساس عملیات ناهمزمان (به عنوان مثال ، واکشی داده ها) ، همیشه از به روزرسانی های عملکردی استفاده کنید تا اطمینان حاصل کنید که با آخرین حالت کار می کنید.
const [data, setData] = useState([]);
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const newData = await response.json();
setData([...data, ...newData]); // Uses stale `data`
}
راه حل: از نحو به روزرسانی عملکردی استفاده کنید
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const newData = await response.json();
setData(prevData => [...prevData, ...newData]); // Always uses the latest state
}
اشتباه 14: استفاده نکردن useState
برای ارائه مشروط با ماشین های دولتی
برای جریان های پیچیده UI (به عنوان مثال ، فرم های چند مرحله ای ، جادوگران) ، استفاده کنید useState
برای اجرای یک دستگاه دولتی ساده. این باعث می شود منطق شما سازمان یافته و قابل پیش بینی باشد.
const [step, setStep] = useState(1);
return (
<div>
{step === 1 && <Step1 />}
{step === 2 && <Step2 />}
{step === 3 && <Step3 />}
</div>
);
راه حل: از یک دستگاه دولتی استفاده کنید
با استفاده از دستگاه حالت ، هر مرحله را به یک جزء نقشه برداری کنید.
const steps = [<Step1 />, <Step2 />, <Step3 />];
const [currentStep, setCurrentStep] = useState(0);
function nextStep() {
setCurrentStep(prevStep => Math.min(prevStep + 1, steps.length - 1));
}
function prevStep() {
setCurrentStep(prevStep => Math.max(prevStep - 1, 0));
}
return (
<div>
{steps[currentStep]}
<button onClick={prevStep} disabled={currentStep === 0}>
Previous
</button>
<button onClick={nextStep} disabled={currentStep === steps.length - 1}>
Next
</button>
</div>
);
اشتباه 15: به روزرسانی دستی خصوصیات تو در تو
هنگام مدیریت حالت پیچیده تو در تو (به عنوان مثال ، اشیاء یا آرایه های عمیقاً تو در تو) ، از یاران ناپذیری مانند استفاده کنید immer
برای ساده تر کردن به روزرسانی ها در حالی که حالت خود را تغییر ناپذیر می کند.
const [user, setUser] = useState({ name: 'John', address: { city: 'New York' } });
function updateCity(newCity) {
setUser(prevUser => ({
...prevUser,
address: { ...prevUser.address, city: newCity }, // Tedious and error-prone
}));
}
راه حل: برای سادگی از Immer استفاده کنید
نصب کردن immer
کتابخانه (npm install immer
) و به روزرسانی های تو در تو را ساده کنید.
import produce from 'immer';
const [user, setUser] = useState({ name: 'John', address: { city: 'New York' } });
function updateCity(newCity) {
setUser(
produce(draft => {
draft.address.city = newCity; // Mutate draft immutably
})
);
}
با من ارتباط برقرار کنید