useState Deep Dive: Beyond Basic Counter Examples ??

useState Deep Dive: Beyond Basic Counter Examples ??

Tired of seeing the same old counter examples for useState? Let's explore advanced patterns that you'll actually use in real-world applications!

1. Object State Management ??

The Wrong Way

function UserProfile() {
  const [user, setUser] = useState({
    name: 'John',
    email: '[email protected]',
    preferences: {
      theme: 'dark',
      notifications: true
    }
  });

  // ? Incorrect: Mutates nested state
  const toggleTheme = () => {
    user.preferences.theme = user.preferences.theme === 'dark' ? 'light' : 'dark';
    setUser(user);
  };
}        

The Right Way

function UserProfile() {
  const [user, setUser] = useState({
    name: 'John',
    email: '[email protected]',
    preferences: {
      theme: 'dark',
      notifications: true
    }
  });

  // ? Correct: Immutable update
  const toggleTheme = () => {
    setUser(prev => ({
      ...prev,
      preferences: {
        ...prev.preferences,
        theme: prev.preferences.theme === 'dark' ? 'light' : 'dark'
      }
    }));
  };
}        

2. State with Validation ???

function PasswordField() {
  const [password, setPassword] = useState({
    value: '',
    isValid: false,
    errors: []
  });

  const validatePassword = (value) => {
    const errors = [];
    if (value.length < 8) errors.push('Too short');
    if (!/\d/.test(value)) errors.push('Needs a number');
    if (!/[A-Z]/.test(value)) errors.push('Needs uppercase');
    return { isValid: errors.length === 0, errors };
  };

  const handleChange = (e) => {
    const value = e.target.value;
    const validation = validatePassword(value);
    setPassword({
      value,
      isValid: validation.isValid,
      errors: validation.errors
    });
  };

  return (
    <div>
      <input 
        type="password"
        value={password.value}
        onChange={handleChange}
        className={password.isValid ? 'valid' : 'invalid'}
      />
      {password.errors.map(error => (
        <div key={error} className="error">{error}</div>
      ))}
    </div>
  );
}        

3. Lazy State Initialization ??

function ExpensiveComponent() {
  // ? Expensive calculation runs on every render
  const [data, setData] = useState(calculateExpensiveInitialState());

  // ? Expensive calculation runs only once
  const [data, setData] = useState(() => calculateExpensiveInitialState());
}        

4. State Queue Management ??

function QueueManager() {
  const [queue, setQueue] = useState([]);
  const [processing, setProcessing] = useState(false);

  const addToQueue = (item) => {
    setQueue(prev => [...prev, item]);
  };

  useEffect(() => {
    if (queue.length > 0 && !processing) {
      setProcessing(true);
      processNextItem();
    }
  }, [queue, processing]);

  const processNextItem = async () => {
    if (queue.length === 0) {
      setProcessing(false);
      return;
    }

    try {
      await processItem(queue[0]);
      setQueue(prev => prev.slice(1));
    } catch (error) {
      console.error(error);
    }
  };
}        

5. State with Undo/Redo ??

function TextEditorWithHistory() {
  const [content, setContent] = useState('');
  const [history, setHistory] = useState({
    past: [],
    future: []
  });

  const handleChange = (newContent) => {
    setHistory(prev => ({
      past: [...prev.past, content],
      future: []
    }));
    setContent(newContent);
  };

  const undo = () => {
    if (history.past.length === 0) return;

    const previous = history.past[history.past.length - 1];
    setHistory(prev => ({
      past: prev.past.slice(0, -1),
      future: [content, ...prev.future]
    }));
    setContent(previous);
  };

  const redo = () => {
    if (history.future.length === 0) return;

    const next = history.future[0];
    setHistory(prev => ({
      past: [...prev.past, content],
      future: prev.future.slice(1)
    }));
    setContent(next);
  };

  return (
    <div>
      <textarea
        value={content}
        onChange={(e) => handleChange(e.target.value)}
      />
      <button onClick={undo} disabled={history.past.length === 0}>
        Undo
      </button>
      <button onClick={redo} disabled={history.future.length === 0}>
        Redo
      </button>
    </div>
  );
}        

6. Computed State Pattern ??

function ShoppingCart() {
  const [items, setItems] = useState([]);
  
  // Computed state
  const totalItems = items.length;
  const totalPrice = items.reduce((sum, item) => sum + item.price, 0);
  const hasDiscountedItems = items.some(item => item.discounted);

  const addItem = (newItem) => {
    setItems(prev => [...prev, newItem]);
  };

  return (
    <div>
      <h2>Cart ({totalItems} items)</h2>
      <p>Total: ${totalPrice}</p>
      {hasDiscountedItems && (
        <p>Some items are discounted! ??</p>
      )}
    </div>
  );
}        


Best Practices ??

  1. Use functional updates for state that depends on previous state
  2. Keep state minimal and derived values computed
  3. Split complex state into multiple useState calls
  4. Use lazy initialization for expensive computations
  5. Maintain immutability when updating objects and arrays


?? Weekly Challenge

Create a form with these features:

  • Multiple input fields with validation
  • Ability to undo/redo changes
  • Show which fields were modified
  • Prevent submission if there are errors
  • Display error summary

Share your solution in the comments!

#React #WebDevelopment #JavaScript #Programming #ReactHooks #FrontEnd #LinkedInLearning


Follow me for more React tips and tutorials! Next week: useEffect Patterns: Data Fetching, Subscriptions & Cleanup ??

Dhruv Patel

"MEAN Stack Developer | Full-Stack Web Applications | Specialist in E-commerce, HRMS & Real-time Systems"

2 周

Insightful

回复

要查看或添加评论,请登录

Dhruv Patel的更多文章