Reasons for Advocating Functional Programming in React
A record of exploring the pros and cons of functional programming and object-oriented programming, and the reasons for choosing functional programming in React
A record of exploring the pros and cons of functional programming and object-oriented programming, and the reasons for choosing functional programming in React
The password you enter is used to open, edit, and delete secret comments.
React has been leaning towards Functional Programming (FP) in recent years.
It actively leverages the advantages of functional approaches from simple UI components to complex application structures.
In this article, we will systematically organize the reasons and grounds for advocating functional programming in React.
The core of functional programming is the 'pure function'. A pure function is a function that always produces the same output for the same input and does not alter external state.
Class Component Testing:
Functional Component:
Functional components allow for separation of logic and rendering, enabling independent testing.
Example of Pure Function:
In functional programming, data is handled immutably by default.
When immutability is maintained, React's optimization tools function very effectively:
Efficient Operation of React.memo:
Accurate Dependency Detection with useMemo and useCallback:
Wrong Method vs Correct Method:
By maintaining immutability, state change detection is possible using only reference comparison («===»).
Deep Comparison vs Reference Comparison:
React uses Object.is() (almost identical to «===») when confirming whether a state has changed:
By maintaining immutability like this, change detection in complex data structures occurs in O(1) time, providing significant performance benefits.
Memoization is an optimization technique that returns cached values instead of recalculating them for the same input. Functional programming assumes pure functions, making memoization highly effective.
and hooks are based on this ideaDifficult to Memoize Non-Pure Functions:
This way, the "immutability + purity" of functional programming aligns with the prerequisites of memoization, strengthening both concepts.
By using functional components and Hooks (useState, useReducer), state management code becomes succinct.
By doing so, UI rendering logic and data logic can be clearly separated, improving readability.
The reason React adopts functional programming is due to clarity of code, ease of testing, optimization, and efficiency in change detection.
The functional paradigm is an effective strategy for modularizing components and controlling complexity.
This is my subjective judgment
Frontend (React) seems suitable for efficiently handling UI rendering, state change detection, optimization, and testing with the functional paradigm.
On the other hand, Backend (Node.js, Java, etc.) is considered practical with object-oriented programming (OOP) for performance issues, resource management, and process flow control.
| Category | Frontend (React, etc.) | Backend (Node.js, Java, etc.) |
|---|---|---|
| Key Considerations | UI Rendering Optimization, State Change Tracking | Performance, Resource Management, Transaction Flow |
| Suitable Paradigm | Functional Programming | Object-Oriented Programming |
| Advantages | Easy Testing, State Change Tracking with Immutability, Component Reusability | Clearly Defined Responsibilities with Class-Based Structure, State Maintenance, Connection-Centric Design, Ease of Structuring Complex Logic |
| Disadvantages | Inconvenient for Complex Flow Operations, Readability Decreases with Indiscriminate Hook Usage | Difficult to Separate State during Testing, Complex Re-Rendering Optimization Structure |
class UserProfile extends React.Component {
state = { name: '', loading: false };
async componentDidMount() {
this.setState({ loading: true });
const user = await fetchUser(this.props.userId);
this.setState({ name: user.name, loading: false });
}
render() {
return <div>{this.state.loading ? 'Loading...' : this.state.name}</div>;
}
}
// Must consider lifecycle and state during testingfunction UserProfile({ userId }) {
const { user, loading } = useUser(userId);
if (loading) return <div>Loading...</div>;
return <div>{user.name}</div>;
}
// Only need to check props during testing (Hook is tested separately)function formatPrice(price, currency = 'USD') {
return `${currency} ${price.toFixed(2)}`;
}
// Predictable results based on input
expect(formatPrice(10.5)).toBe('USD 10.50');
expect(formatPrice(20, 'KRW')).toBe('KRW 20.00');// When maintaining immutability
const TodoItem = React.memo(({ todo, onToggle }) => (
<div onClick={() => onToggle(todo.id)}>
{todo.text} {todo.completed ? '✓' : '○'}
</div>
));
// No re-rendering if props have the same referencefunction TodoList({ todos, filter }) {
// Re-execute filtering only when the todos array is newly created
const filteredTodos = useMemo(() =>
todos.filter(todo => todo.category === filter),
[todos, filter]
);
// No function re-creation if dependencies do not change
const handleToggle = useCallback((id) =>
setTodos(prev => prev.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)),
[]
);
return <div>{/* ... */}</div>;
}// ❌ Direct modification - Optimization tools cannot detect changes
function badUpdate() {
const newTodos = todos;
newTodos[0].completed = true;
setTodos(newTodos); // No re-rendering because the reference is the same
}
// ✅ Creating new objects - Optimization tools work accurately
function goodUpdate() {
setTodos(prev => prev.map((todo, index) =>
index === 0 ? { ...todo, completed: true } : todo
));
}// ❌ Deep Comparison - Checks all properties recursively (slow)
function deepEqual(obj1, obj2) {
// Must compare all key-values of the object
return JSON.stringify(obj1) === JSON.stringify(obj2);
}
// ✅ Reference Comparison - Only checks memory addresses (fast)
function shallowEqual(obj1, obj2) {
return obj1 === obj2; // Ends with a single comparison
}function Counter() {
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: 'John', age: 25 });
// ✅ Primitives automatically ensure immutability
const increment = () => setCount(prev => prev + 1);
// ✅ Objects must be newly created to detect changes
const updateAge = () => setUser(prev => ({ ...prev, age: prev.age + 1 }));
// ❌ This way changes are not detected
const wrongUpdate = () => {
user.age += 1;
setUser(user); // No re-rendering because it is the same reference
};
}function DataTable({ items }) {
// No re-sorting if items have the same reference
const sortedItems = useMemo(() => {
console.log('Sorting executed!'); // Check when it executes
return [...items].sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
return (
<table>
{sortedItems.map(item => (
<tr key={item.id}>
<td>{item.name}</td>
<td>{item.price}</td>
</tr>
))}
</table>
);
}useCallbackfunction ProductList({ products, searchTerm }) {
// Does not refilter if searchTerm or products have not changed
const filteredProducts = useMemo(() => {
console.log('Executing filter!');
return products.filter(p =>
p.name.toLowerCase().includes(searchTerm.toLowerCase())
);
}, [products, searchTerm]);
return <div>{filteredProducts.map(/* ... */)}</div>;
}// ❌ Not pure - depends on external state
let discount = 0.1;
function calculatePrice(price) {
return price * (1 - discount); // References external variable
}
// ✅ Pure - all inputs are passed as parameters
function calculatePrice(price, discount = 0) {
return price * (1 - discount);
}function todoReducer(state, action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, { id: Date.now(), text: action.text, completed: false }];
case 'TOGGLE_TODO':
return state.map(todo =>
todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
);
case 'DELETE_TODO':
return state.filter(todo => todo.id !== action.id);
default:
return state;
}
}
function TodoApp() {
const [todos, dispatch] = useReducer(todoReducer, []);
return (
<div>
<button onClick={() => dispatch({ type: 'ADD_TODO', text: 'New Todo' })}>
Add Todo
</button>
{/* ... */}
</div>
);
}function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const saved = localStorage.getItem(key);
return saved ? JSON.parse(saved) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
// Can be reused in multiple components
function Settings() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
const [language, setLanguage] = useLocalStorage('language', 'ko');
return <div>{/* Settings UI */}</div>;
}A record of the intense 7-week journey: from improving onboarding and infrastructure monitoring to implementing real-time sockets and 3D character optimization.
A record of the emergence, advantages, and disadvantages of UI architecture patterns (MVC, MVP, MVVM, Flux), and their comparative analysis.

A record of building the foundation: from ideation and prototyping to navigating senior feedback and implementing the MVP
An in-depth look at why we normalize vectors, connecting game movement logic with Blender's "Apply Scale."
A reflection on a 6-week team sprint: covering architectural challenges, the nuances of collaboration, and technical growth through senior feedback.
A reflection on the 10-week Boostcamp membership sprint: technical learning, design challenges, burnout, and lessons about using AI effectively.
A personal retrospective on the Boostcamp Web·Mobile Challenge phase: daily missions, CS learning, peer feedback, teamwork, and how I learned to grow alongside AI
A record of exploring the pros and cons of functional programming and object-oriented programming, and the reasons for choosing functional programming in React
My experience preparing for Naver Boostcamp Web·Mobile 10, completing the Basic course, and taking the problem-solving test.
A summary of my contributions to the Githru project during the OSCCA master phase, including UI improvements, issues, and Pull Requests.
My experience during the OSCCA challenge phase, including raising issues and making first Pull Request while exploring the Githru project.
My experience applying to the Open Source Contribution Academy and exploring the Githru VSCode Extension before contributing.
마지막 아티클까지 모두 확인했습니다.