- Published on
React Pattern Overview
- Authors
- Name
- Khánh
React Pattern
Here are some of the most common patterns that I've used in my projects. These patterns can help you to improve the readability, reusability and maintainability your code.
- HOC pattern
- Render Props pattern
- Container Presentational pattern
- Compound Pattern
- Hooks Pattern
- Headless UI
HOC pattern
HOC (Higher Order Component) is a pattern that allows you to reuse code between components. It is a function that takes a component and returns a new component.
I use it more frequency to wrap the component with additional behaviors. This aim to get the input with the component and return the new component with the additional behaviors.
const withLabel = (Component) => {
return (props) => {
return (
<>
<label>{props.label}</label>
<Component {...props} />
</>
)
}
}
const Input = ({ label, ...props }) => {
return <input {...props} />
}
const LabeledInput = withLabel(Input)
Render Props pattern
This is most popular pattern in React. It allows a component to receive a data from a parent component and render it as a child component.
const DataProvider = ({ children }) => {
return <div>{children}</div>
}
const DataConsumer = ({ children }) => {
return <div>{children}</div>
}
const Data = () => {
return (
<DataProvider>
<DataConsumer />
</DataProvider>
)
}
The prop is the <DataConsumer />
component in this case
Container Presentational pattern
This pattern enforce the separation of concerns by separating into two parts:
- Container component: care about what to show to the user.
- Presentational component: care about how to show the data to the user.
// Presentational component
export default function DogImages({ dogs }) {
return dogs.map((dog, i) => <img src={dog} key={i} alt="Dog" />);
}
// Container component
export default class DogImagesContainer extends React.Component {
constructor() {
super();
this.state = {
dogs: []
};
}
componentDidMount() {
fetch("https://dog.ceo/api/breed/labrador/images/random/6")
.then(res => res.json())
.then(({ message }) => this.setState({ dogs: message }));
}
render() {
return <DogImages dogs={this.state.dogs} />;
}
}
Compound Pattern
Organize the component into a group of components that work together.
const ToggleGroup = ({ children }) => {
const [activeButton, setActiveButton] = useState(null);
return (
<div>
{React.Children.map(children, (child, index) =>
React.cloneElement(child, {
isActive: activeButton === index,
onToggle: () => setActiveButton(index),
})
)}
</div>
);
};
const ToggleButton = ({ label, isActive, onToggle }) => {
return (
<button
onClick={onToggle}
style={{ backgroundColor: isActive ? "lightblue" : "white" }}
>
{label}
</button>
);
};
const App = () => {
return (
<ToggleGroup>
<ToggleButton label="Nút 1" />
<ToggleButton label="Nút 2" />
<ToggleButton label="Nút 3" />
</ToggleGroup>
);
};
Hooks Pattern
A way to use React Hooks and custom hooks to manage the state and side effects.
const useToggle = () => {
const [isActive, setIsActive] = useState(false);
return { isActive, setIsActive };
}
Headless UI
A way to separate the UI and the logic.
const ImportLogic = ({ children, ...props }) => {
const [isImporting, setIsImporting] = useState(false);
const handleImport = async () => {
// Your import logic here
};
return children({
isImporting,
error,
handleImport
});
}
const ImportButton = ({ isImporting, error, handleImport }) => {
return (
<div>
{/* import button UI */}
</div>
);
}
const App = () => {
return (
<ImportLogic>
{(
{isImporting, handleImport, error}
) => (
<ImportButton
isImporting={isImporting}
handleImport={handleImport}
error={error}
/>
)}
</ImportLogic>
);
}
Conclusion
By using these patterns, you can improve the readability, reusability and maintainability of your code. Combine them together to get the best result.