React
A JavaScript library for building user interfaces with a UI Components based architecture.
Components
// Function Component
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// Class Component
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
- Function components are simpler and preferred
- Class components needed for some legacy features
Props
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
<Welcome name="Alice" />
- Props are read-only
- Pass data from parent to child components
State
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
- State is mutable and managed within a component
Lifecycle
useEffect(() => {
// Runs after every render
console.log('Component updated');
return () => {
// Cleanup function
console.log('Component will unmount');
};
}, [/* dependency array */]);
- Empty dependency array
[]means run once on mount
Conditional Rendering
function Greeting({ isLoggedIn }) {
return isLoggedIn ? <UserGreeting /> : <GuestGreeting />;
}
- Use ternary operators or
&&for simple conditions - Extract complex logic into separate functions
Lists and Keys
function NumberList({ numbers }) {
return (
<ul>
{numbers.map((number) =>
<li key={number.toString()}>{number}</li>
)}
</ul>
);
}
- Always use keys when rendering lists
- Keys help React identify changed items
Forms
function NameForm() {
const [name, setName] = useState('');
const handleSubmit = (event) => {
event.preventDefault();
console.log('Submitted name:', name);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<button type="submit">Submit</button>
</form>
);
}
- Use controlled components for form inputs
- Handle form submission with
onSubmitevent
Context
const ThemeContext = React.createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
const theme = useContext(ThemeContext);
return <div>Current theme: {theme}</div>;
}
- Use context to pass data through component tree
- Avoid prop drilling for deeply nested components
Hooks
useState
const [state, setState] = useState(initialState);
- Manages State in function components
- Returns current state and a function to update it
- Use when you have simple state logic
useEffect
useEffect(() => {
// Side effect code
return () => {
// Cleanup code (optional)
};
}, [dependencies]);
- Handles side effects (e.g., data fetching, subscriptions)
- Runs after every render by default
- Use empty dependency array
[]to run once on mount - Cleanup function runs before component unmounts
useContext
const value = useContext(MyContext);
- Consumes value from nearest Context.Provider
- Allows accessing context without nesting
- Re-renders when context value changes
useReducer
const [state, dispatch] = useReducer(reducer, initialState);
- Alternative to useState for complex state logic
- Uses a reducer function to determine state updates
- Helpful for managing related state variables
useCallback
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
- Returns a memoized version of the callback
- Useful for optimizing child component re-renders
- Only changes if one of the dependencies has changed
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
- Returns a memoized value
- Recalculates only when dependencies change
- Use for expensive calculations to avoid unnecessary re-computation
useRef
const refContainer = useRef(initialValue);
- Returns a mutable ref object
- Persists across re-renders
- Commonly used to access DOM elements
- Can store any mutable value without causing re-renders
Custom Hooks
function useCustomHook() {
// Hook logic here
return /* relevant values */;
}
- Allows you to extract component logic into reusable functions
- Must start with "use" to follow Hook naming convention
- Can call other Hooks inside custom Hooks
Server Components
async function ServerComponent() {
const data = await fetchDataFromDatabase();
return <div>{data}</div>;
}
import ServerComponent from './server-component';
export default function Page() {
return (
<div>
<h1>My Page</h1>
<ServerComponent />
</div>
);
}
- Introduced in React 18
- Run on the server, not in the browser
- Can access server resources directly (e.g., databases)
- Reduce bundle size by keeping heavy logic on server
- Don't have state or lifecycle methods
- Can't use hooks or handle browser events
- Seamlessly integrate with client components
Key benefits
- Improved performance
- Reduced client-side JavaScript
- Better SEO
- Easier data fetching
Usage notes
- Use for components that don't need interactivity
- Combine with client components for dynamic UIs
- Requires a compatible framework (e.g., Next.js)
Best Practices
- Keep components small and focused
- Lift state up when needed
- Use composition over inheritance
- Avoid premature optimization
- Write tests for your components