Master Component Currying in React
Add to your RSS feed16 February 20253 min read
Table of Contents
Modern React aligns closely with functional programming (FP) principles, making our code cleaner, more readable, and predictable. Some fundamental FP concepts used in React include:
- Declarative Code: Defining what to render instead of how.
- UI = f(state): UI as a function of state.
- Composition: Building complex components from simple, independent ones.
- Memoization: Reusing computed results until inputs change.
Why Functional Programming Matters
Functional programming can seem complex at first—filled with abstract concepts, strict rules, and unfamiliar patterns. But once mastered, it simplifies development and improves code maintainability.
One powerful FP pattern is currying, which we’ll explore in the context of React development.
Understanding Currying
Currying transforms a function that accepts multiple arguments into a sequence of functions, each accepting a single argument:
1 function add(x: number, y: number) {2 return x + y;3 }45 function curriedAdd(x: number) {6 return function (y: number) {7 return x + y;8 };9 }1011 curriedAdd(2)(3); // Returns 5
A related concept is partial application, which pre-fills some arguments of a function in advance. Unlike currying, partial application allows multiple arguments at once.
Applying Currying in React Components
React functional components naturally align with FP principles. They accept props as input and return JSX as output. Using partial application, we can predefine some props while allowing others to be provided later.
Here’s a utility function for partial application in React:
1 import { FC } from 'react';23 function applyPartialProps<T extends Record<string, unknown>, K extends keyof T>(4 Component: FC<T>,5 predefinedProps: Pick<T, K>6 ): FC<Omit<T, K>> {7 return (props) => <Component {...predefinedProps} {...(props as T)} />;8 }
Breaking Down the Function
T
: Represents the full set of props for the original component.K extends keyof T
: Specifies a subset of prop keys to predefine.Pick<T, K>
: Selects only the predefined props.Omit<T, K>
: Excludes the predefined props from T.- Returns a new component expecting only the remaining props.
- During rendering,
predefinedProps
andprops
merge into a full prop set.
Practical Examples
Example 1: Summing Two Numbers
1 type SumProps = {2 num1: number;3 num2: number;4 };56 const Sum: FC<SumProps> = ({ num1, num2 }) => <div>{num1 + num2}</div>;78 const PartialSum = applyPartialProps(Sum, { num1: 5 });910 export default function App() {11 return <PartialSum num2={7} />; // Outputs: 1212 }
Example 2: Preconfigured Buttons
Predefined UI components enhance consistency and reduce repetitive code:
1 type ButtonProps = {2 color: string;3 size: 'small' | 'medium' | 'large';4 variant: 'contained' | 'outlined';5 onClick?: () => void;6 };78 const Button: FC<ButtonProps> = ({ color, size, variant, onClick, children }) => {9 const style = { backgroundColor: color };10 const className = `${size} ${variant}`;1112 return (13 <button style={style} onClick={onClick} className={className}>14 {children}15 </button>16 );17 };1819 const DangerButton = applyPartialProps(Button, {20 color: 'red',21 size: 'large',22 variant: 'contained',23 });2425 export default function App() {26 return <DangerButton onClick={() => alert('Warning!')}>Delete</DangerButton>;27 }
Other Use Cases for applyPartialProps
- Predefined route/navigation components
- Pre-configured API request parameters
- Themed UI components
- Partially applied callback functions
Comparing with Higher-Order Components (HOCs)
This approach resembles Higher-Order Components (HOCs), another FP-inspired pattern.
- HOCs provide broad prop manipulation.
- Partial application is simpler and more readable.
- TypeScript infers which props remain required.
Conclusion
Partial application and currying are powerful FP patterns that improve React component composition. They enhance code readability, reusability, and maintainability.
By integrating these patterns, you can write more declarative and flexible React components while embracing functional programming principles.