React Flashcards
Microfrontends
Micro frontends is an architectural style for frontend development where a web application is divided into smaller, independently deployable modules or “micro apps.” Each micro app is responsible for a distinct part of the user interface and can be developed, deployed, and maintained by different teams.
Key benefits include:
- Independent Development and Deployment: Teams can work on different micro frontends simultaneously, reducing dependencies and speeding up development.
- Technology Agnostic: Different micro frontends can be built using different technologies, allowing teams to choose the best tools for their specific needs.
- Scalability: The architecture allows for scaling specific parts of the application independently.
- Maintainability: Smaller codebases are easier to manage, test, and maintain.
Common implementation techniques include:
- Client-side Composition: Using frameworks like Single-SPA, where the composition happens in the browser.
- Server-side Composition: Assembling the micro frontends on the server before sending the final HTML to the client.
- Edge-side Composition: Using a CDN or edge server to assemble the final page.
HOC
In functional components, Higher-Order Components (HOCs) are implemented using React hooks, specifically the useEffect hook for lifecycle events and useRef for maintaining component references. Here’s an example of how you can create an HOC using functional components and hooks
import React, { useEffect } from 'react'; function withLogging(WrappedComponent) { return function WithLogging(props) { useEffect(() => { console.log(`Component ${WrappedComponent.name} mounted`); }, []); return <WrappedComponent {...props} />; }; } // Usage function MyComponent() { return <div>My Component</div>; } const MyComponentWithLogging = withLogging(MyComponent); export default MyComponentWithLogging;
React.memo
React.memo
is a higher-order component in React that memoizes the rendered output of a component, optimizing performance by preventing unnecessary re-renders. It’s particularly useful for functional components that rely only on props and context. When the props of the component remain the same, React.memo
skips the re-rendering process. This can be beneficial for optimizing React applications, especially when dealing with large lists or complex UI components.
// Memoized component using React.memo const MemoizedComponent = React.memo(MyComponent, (prevProps, nextProps) => { // Custom comparison function // Return true if props are equal (component doesn't need to update) // Return false if props are not equal (component should update) return prevProps.name === nextProps.name && prevProps.count === nextProps.count; });
useReducer
import React, { useReducer } from 'react'; // Reducer function const reducer = (state, action) => { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; case 'reset': return { count: 0 }; default: throw new Error('Unsupported action'); } }; const Counter = () => { // Declare state using useReducer with initial state and reducer function const [state, dispatch] = useReducer(reducer, { count: 0 }); // Dispatch actions to update state const increment = () => { dispatch({ type: 'increment' }); }; const decrement = () => { dispatch({ type: 'decrement' }); }; const reset = () => { dispatch({ type: 'reset' }); }; return ( <div> <p>Count: {state.count}</p> <button onClick={increment}>Increment</button> <button onClick={decrement}>Decrement</button> <button onClick={reset}>Reset</button> </div> ); }; export default Counter;
Virtual scroll using intersection observer
import React, { useState, useEffect, useRef } from 'react'; const items = Array.from({ length: 1000 }, (_, index) => `Item ${index + 1}`); const VirtualScroll = () => { const [visibleItems, setVisibleItems] = useState(items.slice(0, 20)); const [page, setPage] = useState(1); const observer = useRef(); const loadMoreItems = (entries) => { const [entry] = entries; if (entry.isIntersecting) { const nextPage = page + 1; const newItems = items.slice(0, nextPage * 20); setVisibleItems(newItems); setPage(nextPage); } }; useEffect(() => { const options = { root: null, rootMargin: '0px', threshold: 1.0 }; observer.current = new IntersectionObserver(loadMoreItems, options); if (observer.current && observer.current.observe) { observer.current.observe(document.querySelector('#end-of-list')); } return () => observer.current.disconnect(); }, [page]); return ( <div> <ul> {visibleItems.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> <div id="end-of-list" style={{ height: '20px' }}></div> </div> ); }; export default VirtualScroll;