When writing React component, one of the common thing that happen is that the component that you write has became a big fat chunk, causing it harder to read and understand.
When that happens, it is always advised for you to split the big component into few smaller component so it is easier to understand. Besides, the smaller components could be reused elsewhere.
Sometimes, it is quite obvious how to do it by just moving your code into another component. But sometimes it is not so obvious what is the best way to split the code.
For instance, a scenario that can make splitting component more complicated is that your onClick
handler for your child component need to know the id of the parent, which is a common requirement when you have some nested data structure.
In those case, currying may help you to split the component in a clean way.
What is currying
Currying is a functional programming technique to transform a function that takes multiple arguments into a sequence of functions.
For instance, a typical add function and usage looks like below:
const add = (x, y) => {
return x + y;
}
add(2, 3); // 5
Using currying, the add function can be rewrited as below:
const add = x => y => {
return x + y;
}
add(2)(3); // 5
Now you understand what is currying, let's see how it can help us in splitting component.
Intro to Example
To help you understand how currying may help, assuming you have the data structure below.
data = [
{
id: 1,
name: "Parent 1",
sublist: [
{
id: 11,
name: "Child 1",
},
{
id: 12,
name: "Child 2",
}
]
},
{
id: 2,
name: "Parent 2",
sublist: [
{
id: 21,
name: "Child 3",
},
{
id: 22,
name: "Child 24",
}
]
}
];
And the initial components looks like this: (I know it is not so big in this example, just imagine the data structure is longer and you need to display more data in the component)
const FatComponent = ({ data }) => {
const updateItem = (parentId, childId) => {
someFunction(parentId, childId);
};
return data.map(parent => (
<div>
<span>name: {parent.name}</span>
<div>
{parent.sublist.map(item => (
<div>
<span>{item.name}</span>
<button onClick={() => this.updateItem(parent.id, item.id)}>remove</button>
</div>
))}
</div>
</div>
));
}
Attempt to split the component
We can split the component like below:
const FatComponent = ({ data }) => {
const updateItem = (parentId, itemId) => {
someFunction(parentId, childId);
};
return data.map(parent => <Parent updateItem={updateItem} {...parent} />);
};
const Parent = ({ id, name, sublist, updateItem }) => (
<div>
<span>{name}</span>
<div>
{sublist.map(item => <Item updateItem={updateItem} parentId={id} {...item} />)}
</div>
</div>
);
const Item = ({ name, id, updateItem, parentId }) => (
<div>
<span>{name}</span>
<button onClick={() => updateItem(parentId, id)}>remove</button>
</div>
);
However, this solution is not clean because it makes Item
become tightly coupled to the parent, as the parent component must pass down updateItem
and parentId
props to Item
component.
Ideally, Item
should accept buttonOnClick
props and attach it to the button onClick
handler, like below:
const Item = ({ name, id, buttonOnClick }) => (
<div>
<span>{name}</span>
<button onClick={buttonOnClick}>remove</button>
</div>
);
This would makes Item flexible and more likely to be reused for other components.
Solution - Using currying
By using currying, we would able to achieve that:
const FatComponent = ({ data }) => {
const updateItem = parentId => itemId => () => {
someFunction(parentId, itemId);
};
return data.map(parent => <Parent updateItem={updateItem(parent.id)} {...parent} />);
};
const Parent = ({ name, sublist, updateItem }) => (
<div>
<span>{name}</span>
<div>
{sublist.map(item => <Item buttonOnClick={updateItem(item.id)} parentId={id} {...item} />)}
</div>
</div>
);
const Item = ({ name, id, buttonOnClick }) => (
<div>
<span>{name}</span>
<button onClick={buttonOnClick}>remove</button>
</div>
);
Clean and sweet!
Final Words
Even though functional programming is not required for you to coding in React, however, learning more of functional programming would help you to write cleaner and better React code.
Happy coding!
Top comments (1)
This is spot on. People who just picked up React commonly make components with lots of jsx, like you would if you were writing the entire html for a page in one file. If you don't split that up into logical compokents you are missing half the point of React. (The other half is how React renders after each state change, makikng you write declarative code.)