You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When building a React application, separating the logic and state management from the UI can make your code easier to manage, test, and reuse. This is where the view model pattern comes in handy. By using a custom hook as a view model, you can keep your components focused on displaying the UI while the hook handles all the complex logic and state. Let's break down how to do this with a simple example.
Creating custom hook
A custom hook is a JavaScript function that uses React hooks like useState and useEffect to manage state and logic. In this example, we’ll create a custom hook to manage a list of items. The hook will handle fetching items from an API, adding new items, and removing items.
Here’s how you can create the custom hook:
// useItemsViewModel.jsimport{useState,useEffect}from'react';constuseItemsViewModel=()=>{const[items,setItems]=useState([]);const[loading,setLoading]=useState(true);const[error,setError]=useState(null);// Fetch items from an APIconstfetchItems=async()=>{setLoading(true);try{constresponse=awaitfetch('/api/items');constdata=awaitresponse.json();setItems(data);}catch(err){setError(err.message);}finally{setLoading(false);}};// Add a new itemconstaddItem=async(item)=>{try{constresponse=awaitfetch('/api/items',{method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify(item),});constnewItem=awaitresponse.json();setItems((prevItems)=>[...prevItems,newItem]);}catch(err){setError(err.message);}};// Remove an itemconstremoveItem=async(id)=>{try{awaitfetch(`/api/items/${id}`,{method: 'DELETE',});setItems((prevItems)=>prevItems.filter((item)=>item.id!==id));}catch(err){setError(err.message);}};useEffect(()=>{fetchItems();},[]);return{
items,
loading,
error,
addItem,
removeItem,};};exportdefaultuseItemsViewModel;
In this hook:
items, loading, and error are state variables to store the list of items, loading status, and any errors.
fetchItems, addItem, and removeItem are functions to fetch, add, and remove items.
The useEffect hook ensures that items are fetched when the hook is first used.
Using the Custom Hook in a Component
Now, let's create a component that uses this custom hook to display the list of items and allows users to add or remove items.
Testing a custom hook in React, like the view model we created, involves using a testing library like @testing-library/react-hooks along with a testing framework like Jest. This allows you to isolate the logic in the hook and verify its behavior.
Here’s how you can write unit tests for the useItemsViewModel custom hook.
Here's how you can write tests for the custom hook:
// useItemsViewModel.test.jsimport{renderHook,act}from'@testing-library/react-hooks';importuseItemsViewModelfrom'./useItemsViewModel';// Mock fetch APIglobal.fetch=jest.fn();constmockItems=[{id: 1,name: 'Item 1'},{id: 2,name: 'Item 2'}];beforeEach(()=>{fetch.mockClear();});test('should fetch items successfully',async()=>{fetch.mockResolvedValueOnce({json: async()=>mockItems,});const{ result, waitForNextUpdate }=renderHook(()=>useItemsViewModel());// Initially loading should be trueexpect(result.current.loading).toBe(true);// Wait for the fetch to completeawaitwaitForNextUpdate();// Verify the hook state after fetching itemsexpect(result.current.items).toEqual(mockItems);expect(result.current.loading).toBe(false);expect(result.current.error).toBe(null);});test('should handle fetch error',async()=>{fetch.mockRejectedValueOnce(newError('Failed to fetch'));const{ result, waitForNextUpdate }=renderHook(()=>useItemsViewModel());// Initially loading should be trueexpect(result.current.loading).toBe(true);// Wait for the fetch to completeawaitwaitForNextUpdate();// Verify the hook state after the fetch errorexpect(result.current.items).toEqual([]);expect(result.current.loading).toBe(false);expect(result.current.error).toBe('Failed to fetch');});test('should add a new item',async()=>{fetch.mockResolvedValueOnce({json: async()=>mockItems,});const{ result, waitForNextUpdate }=renderHook(()=>useItemsViewModel());// Wait for the initial fetch to completeawaitwaitForNextUpdate();constnewItem={id: 3,name: 'Item 3'};fetch.mockResolvedValueOnce({json: async()=>newItem,});awaitact(async()=>{awaitresult.current.addItem(newItem);});// Verify the hook state after adding an itemexpect(result.current.items).toEqual([...mockItems,newItem]);});test('should remove an item',async()=>{fetch.mockResolvedValueOnce({json: async()=>mockItems,});const{ result, waitForNextUpdate }=renderHook(()=>useItemsViewModel());// Wait for the initial fetch to completeawaitwaitForNextUpdate();fetch.mockResolvedValueOnce({json: async()=>({}),});awaitact(async()=>{awaitresult.current.removeItem(1);});// Verify the hook state after removing an itemexpect(result.current.items).toEqual(mockItems.filter(item=>item.id!==1));});
By using a custom hook as a view model, you encapsulate all the state management and business logic within the hook. This makes your components focused on rendering the UI, leading to cleaner, more maintainable, and reusable code. The custom hook handles all the complex logic, allowing the component to remain simple and focused on what it does best—displaying the UI.
The text was updated successfully, but these errors were encountered:
When building a React application, separating the logic and state management from the UI can make your code easier to manage, test, and reuse. This is where the view model pattern comes in handy. By using a custom hook as a view model, you can keep your components focused on displaying the UI while the hook handles all the complex logic and state. Let's break down how to do this with a simple example.
Creating custom hook
A custom hook is a JavaScript function that uses React hooks like useState and useEffect to manage state and logic. In this example, we’ll create a custom hook to manage a list of items. The hook will handle fetching items from an API, adding new items, and removing items.
Here’s how you can create the custom hook:
In this hook:
Using the Custom Hook in a Component
Now, let's create a component that uses this custom hook to display the list of items and allows users to add or remove items.
In this component:
Integrating into Your App
Finally, integrate the component into your main application
Testing view model
Testing a custom hook in React, like the view model we created, involves using a testing library like
@testing-library/react-hooks
along with a testing framework like Jest. This allows you to isolate the logic in the hook and verify its behavior.Here’s how you can write unit tests for the useItemsViewModel custom hook.
Here's how you can write tests for the custom hook:
By using a custom hook as a view model, you encapsulate all the state management and business logic within the hook. This makes your components focused on rendering the UI, leading to cleaner, more maintainable, and reusable code. The custom hook handles all the complex logic, allowing the component to remain simple and focused on what it does best—displaying the UI.
The text was updated successfully, but these errors were encountered: