react-patterns
React component patterns are essential for organizing code, improving reusability, and managing state and props efficiently. Here are ten common patterns that could come up in an interview:
1. Function Components
Using simple functions to create components.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
2. Class Components
Using ES6 classes to create components.
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
3. Higher-Order Components (HOC)
Taking a component and returning a new component with additional properties or behavior.
function withLogging(WrappedComponent) {
return class extends React.Component {
componentDidMount() {
console.log('Component did mount');
}
render() {
return <WrappedComponent {...this.props} />;
}
};
}
4. Render Props
Using a function prop that a component uses to know what to render.
function List({ render }) {
const items = ['Alice', 'Bob', 'Charlie'];
return <div>{items.map(render)}</div>;
}
5. Container/Presentational Components
Separating components into ones that handle logic (containers) and ones that handle rendering (presentational).
// Container component
class UserContainer extends React.Component {
state = { users: [] };
// Logic to fetch users...
render() {
return <UserList users={this.state.users} />;
}
}
// Presentational component
function UserList({ users }) {
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
6. Controlled Components
Components where React controls the state of form elements.
class Form extends React.Component {
state = { value: '' };
handleChange = (event) => {
this.setState({ value: event.target.value });
};
render() {
return <input type="text" value={this.state.value} onChange={this.handleChange} />;
}
}
7. Uncontrolled Components
Components where form data is handled by the DOM, not by React.
class Form extends React.Component {
inputRef = React.createRef();
handleSubmit = (event) => {
alert('A name was submitted: ' + this.inputRef.current.value);
event.preventDefault();
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" ref={this.inputRef} />
<button type="submit">Submit</button>
</form>
);
}
}
8. Compound Components
Components that work together to form a complete UI, sharing implicit state.
function Tabs({ children }) {
const [activeIndex, setActiveIndex] = React.useState(0);
return React.Children.map(children, (child, index) =>
React.cloneElement(child, {
isActive: index === activeIndex,
onActivate: () => setActiveIndex(index)
})
);
}
function Tab({ isActive, onActivate, children }) {
return <div onClick={onActivate}>{isActive ? <b>{children}</b> : children}</div>;
}
9. Context API
Providing a way to pass data through the component tree without having to pass props down manually at every level.
const MyContext = React.createContext();
function App() {
return (
<MyContext.Provider value="Hello from context!">
<ChildComponent />
</MyContext.Provider>
);
}
function ChildComponent() {
return (
<MyContext.Consumer>
{value => <div>{value}</div>}
</MyContext.Consumer>
);
}
10. Hooks (useState, useEffect, etc.)
Functional components using hooks to manage state and lifecycle events.
function Counter() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
const id = setInterval(() => {
setCount(c => c + 1);
}, 1000);
return () => clearInterval(id);
}, []);
return <h1>{count}</h1>;
}
These patterns are frequently discussed in React interviews to evaluate a candidate's understanding of React best practices, component composition, and state management.