🌶️ Currying React Components


Introduction
If you’ve ever written repetitive or overly verbose React components and felt "there must be a cleaner way", then currying might just be your new best friend.
In this article, we’ll explore:
What currying is (in plain English)
How currying applies to React components
Why this pattern is powerful
Tons of examples (from basic to advanced)
Use-cases and gotchas
Let’s dive in! 💡
🧠 What is Currying?
In functional programming, currying is the process of transforming a function with multiple arguments into a sequence of functions, each taking one argument at a time.
Traditional Function
function greet(greeting, name) {
return `${greeting}, ${name}`;
}
greet('Hello', 'Alice'); // "Hello, Alice"
Curried Function
const greet = (greeting) => (name) => `${greeting}, ${name}`;
greet('Hello')('Alice'); // "Hello, Alice"
Why is this useful? Because you can partially apply arguments and create specialized versions of functions easily.
🍱 Currying in React Components
Now let’s translate that concept to React.
Traditional Component
function Button({ variant, size, children }) {
return <button className={`${variant} ${size}`}>{children}</button>;
}
You use it like:
<Button variant="primary" size="sm">Click Me</Button>
But what if you're always using variant="primary"
throughout your app? Currying to the rescue.
🔁 Currying a Component
Step 1: Make it a curried function
const withVariant = (variant) => (props) => {
return <Button {...props} variant={variant} />;
};
Now you can create a pre-configured component:
const PrimaryButton = withVariant('primary');
<PrimaryButton size="sm">Click Me</PrimaryButton>
✅ DRY (Don't Repeat Yourself)
✅ Easy to theme
✅ Improves readability
🔧 Real-World Examples
1. ✅ Pre-styled Button Variants
const withButtonVariant = (variant) => (size) => ({ children, ...rest }) => (
<button className={`btn ${variant} ${size}`} {...rest}>
{children}
</button>
);
const PrimarySmallButton = withButtonVariant('primary')('sm');
const DangerLargeButton = withButtonVariant('danger')('lg');
<PrimarySmallButton>Save</PrimarySmallButton>
<DangerLargeButton>Delete</DangerLargeButton>
2. 🌍 Themed Components (like translation or directionality)
const withLang = (lang) => (Component) => (props) => {
return <Component {...props} lang={lang} />;
};
const Greeting = ({ lang }) => (
<p>{lang === 'en' ? 'Hello!' : '¡Hola!'}</p>
);
const EnglishGreeting = withLang('en')(Greeting);
const SpanishGreeting = withLang('es')(Greeting);
<EnglishGreeting />
<SpanishGreeting />
3. 🧱 Higher-Order Component Factory
Currying also makes it easier to compose HOCs in a readable way.
const withBorder = (color) => (Component) => (props) => (
<div style={{ border: `2px solid ${color}` }}>
<Component {...props} />
</div>
);
const withPadding = (padding) => (Component) => (props) => (
<div style={{ padding }}>
<Component {...props} />
</div>
);
const Title = ({ children }) => <h1>{children}</h1>;
const StyledTitle = withBorder('blue')(withPadding('20px')(Title));
<StyledTitle>Welcome</StyledTitle>
4. 🔁 Conditional Logic
You can even curry for conditional rendering:
const withAuth = (isAuthenticated) => (Component) => (props) =>
isAuthenticated ? <Component {...props} /> : <p>Please log in</p>;
const Dashboard = () => <div>Welcome to the dashboard</div>;
const ProtectedDashboard = withAuth(true)(Dashboard);
🔄 Currying with Hooks
Currying isn’t just for components—it can work beautifully with hooks too.
const useFetcher = (baseURL) => (endpoint) => {
const [data, setData] = useState(null);
useEffect(() => {
fetch(`${baseURL}/${endpoint}`)
.then((res) => res.json())
.then(setData);
}, [endpoint]);
return data;
};
// Usage
const useGitHub = useFetcher('https://api.github.com');
const userData = useGitHub('users/octocat');
✨ Benefits of Currying React Components
✅ Code Reuse: Create mini "component factories"
✅ Clarity: Break down logic and props cleanly
✅ Partial Application: Pre-configure components without wrappers
✅ Testability: Smaller units are easier to test
✅ Better Theming: Build dynamic design systems with less code
⚠️ Gotchas & When Not to Curry
❌ Too much abstraction can make code harder to read for beginners.
❌ Don’t curry everything—use it when it clearly improves DX (developer experience).
⚠️ Be careful with props overwriting—always document what’s hardcoded via curry.
// This will override user's variant prop unintentionally
const CurriedButton = withVariant('primary');
// Be mindful of prop merging priority
🧪 Advanced Pattern: Currying with Composition Libraries
If you're using libraries like lodash/fp
or ramda
, currying becomes even more powerful.
import { compose } from 'ramda';
const enhance = compose(
withBorder('green'),
withPadding('10px'),
withLang('en')
);
const EnhancedComponent = enhance(Title);
✅ Summary
Currying is a functional pattern that fits beautifully into React, especially when:
You want to pre-configure a component
You're building design systems
You’re composing HOCs or hooks
You love writing clean, declarative code
It’s one of those underrated tricks that, once mastered, makes you feel like a React wizard 🧙♂️.
Subscribe to my newsletter
Read articles from Utkarsh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Utkarsh
Utkarsh
I'm a MERN Stack developer and technical writer that loves to share his thoughts in words on latest trends and technologies. For queries and opportunities, I'm available at r.utkarsh.0010@gmail.com