Post

Funtions Vs Procedures

Functions vs. Procedures in JavaScript and React

TL;DR



1. What are Functions and Procedures?

  • Functions:
    • Functions are blocks of code that return a value and don’t modify outside state if they’re pure.
    • Usage: calculations, transforming data, returning values based on inputs.
  • Procedures:
    • Procedures are also functions, but they trigger changes or side effects.
    • Usage: logging, fetching data, modifying global variables, working with the DOM, updating the UI, updating state, making API calls, performing actions based on events.

2. Examples of Functions vs. Procedures

Example of a Pure Function:

This function only relies on its inputs and has no side effects.

1
2
3
4
5
  function add(a, b) {
      return a + b;
  }
  // Example usage:
  add(2, 3); // returns 5

In React: Pure Function for Data Transformation

1
2
3
  function capitalize(str) {
      return str.charAt(0).toUpperCase() + str.slice(1);
  }

#### Example of a Procedure This function performs a side effect (logging to the console).

1
2
3
4
5
  function logMessage(message) {
      console.log(message);
  }
  // Example usage:
  logMessage("Hello, World!"); // prints "Hello, World!" to console

Procedure for Updating State:

1
2
3
4
5
  const [count, setCount] = useState(0);

  function incrementCount() {
      setCount(count + 1);
  }

3. Why Differentiate Functions from Procedures?

  • Cleaner, Testable Code: Separating logic (functions) from actions (procedures) allows for easier testing and debugging.
  • Better Reusability: Pure functions can be reused across components or even projects.
  • More Predictable: Pure functions return the same output for the same input, making behavior easier to predict and test.

4. Pure Functions in JavaScript and React

  • Characteristics of Pure Functions:
    • Always return the same output for the same input.
    • Do not modify external state or produce side effects.
  • Example of a Pure Function:
    1
    2
    3
    
    function getDiscountedPrice(price, discountRate) {
        return price - (price * discountRate);
    }
    

In React:

  • Pure Functional Component:
    1
    2
    3
    
    function Greeting({ name }) {
        return <h1>Hello, {name}!</h1>;
    }
    
    • This component is pure because it does not modify any outside state and only relies on its name prop.

5. Procedural Code in JavaScript and React

  • Common Uses: Found where we need to perform actions or update application state without needing to return values.
  • Best Practice: Encapsulate code that produces side effects in functions with clear purposes, and isolate them as much as possible.

In JavaScript:

  • Example of a Procedure for Updating the DOM:
    1
    2
    3
    4
    
    function updateTitle(newTitle) {
        document.title = newTitle;
    }
    // No return value; purely an action
    

In React:

  • State Updater Procedure in useEffect:
    1
    2
    3
    4
    5
    6
    
    useEffect(() => {
        document.title = `
        Count Clicker
        Count = ++${count}
        `;
    }, [count]); // React watches count and performs a side effect when it changes
    
  • Procedure for Fetching Data:
    1
    2
    3
    4
    5
    6
    
    function fetchData(url) {
        fetch(url)
            .then(response => response.json())
            .then(data => console.log(data))
            .catch(error => console.error("Error:", error));
    }
    

6. Functional Programming in JavaScript

  • Pure Functions: Functions with no side effects and consistent return values.
  • Example of a Pure Function:
    1
    2
    3
    
    function double(x) {
        return x * 2;
    }
    
    • Benefit: Easy to test and debug.
  • Procedural Example in React: When interacting with APIs or updating the DOM
    1
    2
    3
    4
    5
    6
    7
    8
    
    useEffect(() => {
        async function fetchData() {
            const response = await fetch("https://api.example.com/data");
            const data = await response.json();
            setData(data); // updates state (side effect)
        }
        fetchData();
    }, []); // dependency array ensures it only runs once
    


Core Concepts

Flash Cards

1. Understanding Functions vs Procedures

Pure Functions

  • Return a value based solely on inputs
  • Have no side effects
  • Same input always produces same output
  • Are predictable and testable
    1
    2
    3
    4
    
    // Pure function example
    function calculateTotal(price, tax) {
      return price + (price * tax);
    }
    

Procedures

  • Perform actions or side effects
  • May not return a value
  • Change external state
  • Often handle UI updates, API calls, or state management
    1
    2
    3
    4
    5
    
    // Procedure example
    function saveUserData(userData) {
      localStorage.setItem('user', JSON.stringify(userData));
      console.log('User data saved');
    }
    

2. Side Effects in JavaScript

Common side effects include:

  • Modifying DOM elements
  • Making API calls
  • Writing to localStorage
  • Updating global variables
  • Writing to databases
  • Logging
1
2
3
4
5
6
7
8
9
// Side effect examples
function updateUIElement(id, value) {
    document.getElementById(id).textContent = value; // DOM modification
}

async function fetchUserData() {
    const response = await fetch('/api/user'); // API call
    return response.json();
}

3. React-Specific Patterns

Pure Components

1
2
3
4
5
6
7
8
9
// Pure component
function PriceDisplay({ price, currency }) {
    const formattedPrice = new Intl.NumberFormat('en-US', {
        style: 'currency',
        currency
    }).format(price);
    
    return <div>{formattedPrice}</div>;
}

Components with Side Effects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Component with side effects
function UserProfile({ userId }) {
    const [user, setUser] = useState(null);
    
    useEffect(() => {
        // Procedure wrapped in useEffect
        async function loadUser() {
            const data = await fetchUserData(userId);
            setUser(data);
        }
        loadUser();
    }, [userId]);
    
    return <div>{user?.name}</div>;
}

4. Best Practices

Function Organization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Separate pure functions from procedures
const userUtils = {
    // Pure function for validation
    isValidEmail: (email) => {
        return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
    },
    
    // Procedure for API interaction
    saveUser: async (userData) => {
        await fetch('/api/users', {
            method: 'POST',
            body: JSON.stringify(userData)
        });
    }
};

Error Handling

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Pure function with error handling
function divideNumbers(a, b) {
    if (b === 0) {
        throw new Error('Division by zero');
    }
    return a / b;
}

// Procedure with error handling
async function saveWithLinearRetry(data, maxRetries = 3, delay = 1000) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            const result = await saveData(data);
            return result;
        } catch (error) {
            // If this is the last retry, throw the error
            if (i === maxRetries - 1) {
                throw new Error(`Failed after ${maxRetries} attempts: ${error.message}`);
            }
            
            // Wait for the specified delay before next retry
            await new Promise(resolve => setTimeout(resolve, delay));
            console.log(`Attempt ${i + 1} failed, retrying...`);
        }
    }
}

5. Testing Considerations

Testing Pure Functions

1
2
3
4
5
6
// pure function
describe('calculateTotal', () => {
    test('calculates correct total with tax', () => {
        expect(calculateTotal(100, 0.1)).toBe(110);
    });
});

Testing Procedures

1
2
3
4
5
6
7
8
9
10
11
12
// requires mocking
describe('saveUserData', () => {
    beforeEach(() => {
        localStorage.clear();
    });
    
    test('saves user data to localStorage', () => {
        const userData = { name: 'John' };
        saveUserData(userData);
        expect(JSON.parse(localStorage.getItem('user'))).toEqual(userData);
    });
});

1 second advice

  1. Composition Over Procedures
    • Try to compose multiple pure functions instead of creating complex procedures
    • Makes code more maintainable and testable
  2. State Management
    • Keep state changes isolated and predictable
    • Use React’s useState for local state
    • Consider Redux/Context for global state
  3. Debugging
    • Pure functions are easier to debug (input → output)
    • Log procedures carefully to track side effects
    • Use browser dev tools to monitor network calls and state changes
  4. Performance
    • Pure functions can be memoized (React.memo, useMemo)
    • Procedures often need careful optimization (useCallback)
    • Consider the cost of side effects in your application
  5. Documentation
    • Document side effects clearly
    • Specify return types and parameters
    • Include examples for complex functions

This post is licensed under CC BY 4.0 by the author.