React 19 引入了幾個強大的新鉤子,徹底改變了我們在應用程式中處理表單和管理樂觀更新的方式。在本部落格中,我們將探討 useFormStatus、useActionState 和 useOptimistic - 三個使我們的 React 應用程式響應更快且用戶友好的鉤子。
useFormStatus 掛鉤提供有關表單提交的即時信息,使創建響應式且可訪問的表單變得更加容易。讓我們探討一下這個鉤子如何改進 React 18 的表單處理能力。
function SubmitButton() { const { pending } = useFormStatus(); return ( <button disabled={pending}> {pending ? 'Submitting...' : 'Submit'} </button> ); } function SignupForm() { return ( <form action={async (formData) => { await submitSignupData(formData); }}> <input name="email" type="email" /> <input name="password" type="password" /> <SubmitButton /> </form> ); }
在 React 18 中,您需要使用 useState 手動管理載入狀態。新的 useFormStatus 掛鉤會自動處理此問題,從而減少樣板程式碼。
function FormStatus() { const { pending, data, method } = useFormStatus(); return ( <div role="status"> {pending && <span>Submitting via {method}...</span>} {!pending && data && <span>Last submission: {new Date().toLocaleString()}</span>} </div> ); } function ContactForm() { return ( <form action={async (formData) => { await submitContactForm(formData); }}> <textarea name="message" /> <FormStatus /> <SubmitButton /> </form> ); }
function ValidationStatus() { const { pending, validationErrors } = useFormStatus(); return ( <div role="alert"> {validationErrors?.map((error, index) => ( <p key={index} className="error">{error}</p> ))} </div> ); } function RegistrationForm() { return ( <form action={async (formData) => { const errors = validateRegistration(formData); if (errors.length) throw errors; await register(formData); }}> <input name="username" /> <input name="email" type="email" /> <ValidationStatus /> <SubmitButton /> </form> ); }
function FormProgress() { const { pending, step, totalSteps } = useFormStatus(); return ( <div className="progress-bar"> <div className="progress" > <h3> Example 5: File Upload Progress </h3> <pre class="brush:php;toolbar:false">function UploadProgress() { const { pending, progress } = useFormStatus(); return ( <div> {pending && progress && ( <div className="upload-progress"> <div className="progress-bar" > <h2> useActionState: Managing Action Results </h2> <p>The useActionState hook provides a way to track the state of form actions and server mutations, making it easier to handle success and error states.</p> <h3> Example 1: Basic Action State </h3> <pre class="brush:php;toolbar:false">function SubmissionStatus() { const state = useActionState(); return ( <div> {state.status === 'success' && <p>Submission successful!</p>} {state.status === 'error' && <p>Error: {state.error.message}</p>} </div> ); } function CommentForm() { return ( <form action={async (formData) => { await submitComment(formData); }}> <textarea name="comment" /> <SubmissionStatus /> <SubmitButton /> </form> ); }
function ActionHistory() { const state = useActionState(); return ( <div> <h3>Recent Actions</h3> <ul> {state.history.map((action, index) => ( <li key={index}> {action.type} - {action.timestamp} {action.status === 'error' && ` (Failed: ${action.error.message})`} </li> ))} </ul> </div> ); }
function RetryableAction() { const state = useActionState(); return ( <div> {state.status === 'error' && ( <button onClick={() => state.retry()} disabled={state.retrying} > {state.retrying ? 'Retrying...' : 'Retry'} </button> )} </div> ); }
function ActionQueue() { const state = useActionState(); return ( <div> <h3>Pending Actions</h3> {state.queue.map((action, index) => ( <div key={index}> {action.type} - Queued at {action.queuedAt} <button onClick={() => action.cancel()}>Cancel</button> </div> ))} </div> ); }
function ActionStats() { const state = useActionState(); return ( <div> <h3>Action Statistics</h3> <p>Success Rate: {state.stats.successRate}%</p> <p>Average Duration: {state.stats.avgDuration}ms</p> <p>Total Actions: {state.stats.total}</p> </div> ); }
useOptimistic 掛鉤可以在等待伺服器回應時立即更新 UI,從而創建響應更快的使用者體驗。
function TodoList() { const [todos, setTodos] = useState([]); const [optimisticTodos, addOptimisticTodo] = useOptimistic( todos, (state, newTodo) => [...state, newTodo] ); async function addTodo(formData) { const newTodo = { id: Date.now(), text: formData.get('todo'), completed: false }; addOptimisticTodo(newTodo); await saveTodo(newTodo); } return ( <div> <form action={addTodo}> <input name="todo" /> <button type="submit">Add Todo</button> </form> <ul> {optimisticTodos.map(todo => ( <li key={todo.id}>{todo.text}</li> ))} </ul> </div> ); }
function LikeButton({ postId, initialLikes }) { const [likes, setLikes] = useState(initialLikes); const [optimisticLikes, addOptimisticLike] = useOptimistic( likes, (state) => state + 1 ); async function handleLike() { addOptimisticLike(); await likePost(postId); } return ( <button onClick={handleLike}> {optimisticLikes} Likes </button> ); }
function CommentThread({ postId }) { const [comments, setComments] = useState([]); const [optimisticComments, addOptimisticComment] = useOptimistic( comments, (state, newComment) => [...state, newComment] ); async function submitComment(formData) { const comment = { id: Date.now(), text: formData.get('comment'), pending: true }; addOptimisticComment(comment); await saveComment(postId, comment); } return ( <div> <form action={submitComment}> <textarea name="comment" /> <button type="submit">Comment</button> </form> {optimisticComments.map(comment => ( <div key={comment.id}> <h3> Example 4: Optimistic Shopping Cart </h3> <pre class="brush:php;toolbar:false">function ShoppingCart() { const [cart, setCart] = useState([]); const [optimisticCart, updateOptimisticCart] = useOptimistic( cart, (state, update) => { const { type, item } = update; switch (type) { case 'add': return [...state, item]; case 'remove': return state.filter(i => i.id !== item.id); case 'update': return state.map(i => i.id === item.id ? item : i); default: return state; } } ); async function updateCart(type, item) { updateOptimisticCart({ type, item }); await saveCart({ type, item }); } return ( <div> {optimisticCart.map(item => ( <div key={item.id}> {item.name} - ${item.price} <button onClick={() => updateCart('remove', item)}>Remove</button> </div> ))} </div> ); }
function UserSettings() { const [settings, setSettings] = useState({}); const [optimisticSettings, updateOptimisticSetting] = useOptimistic( settings, (state, update) => ({ ...state, [update.key]: update.value }) ); async function updateSetting(key, value) { updateOptimisticSetting({ key, value }); await saveSettings({ [key]: value }); } return ( <div> <div> <label> Theme: <select value={optimisticSettings.theme} onChange={e => updateSetting('theme', e.target.value)} > <option value="light">Light</option> <option value="dark">Dark</option> </select> </label> </div> <div> <label> Notifications: <input type="checkbox" checked={optimisticSettings.notifications} onChange={e => updateSetting('notifications', e.target.checked)} /> </label> </div> </div> ); }
在應用程式中使用這些鉤子時,請記住查看官方 React 文件以獲取最新資訊和最佳實踐。
編碼快樂!
以上是了解 React 新 Hooks的詳細內容。更多資訊請關注PHP中文網其他相關文章!