Popular Searches
Popular Course Categories
Popular Courses

Functions, Arrow Functions, and Callback Functions

Functions, Arrow Functions, and Callback Functions

JavaScript and Modern ES6+ Fundamentals

Functions, Arrow Functions, and Callback Functions in JavaScript for React Native

Course: React Native Training

Topic: Functions, Arrow Functions, and Callback Functions

Course Link: React Native Training at JustAcademy

Demo Link: Register for a Free Course Demo

Website: JustAcademy


1. Introduction to Functions in JavaScript

Functions are one of the most important concepts in JavaScript and React Native development. A function is a reusable block of code designed to perform a particular task. Instead of writing the same instructions repeatedly, developers can place the instructions inside a function and execute them whenever required.

In React Native, functions are used to handle button presses, validate forms, process user input, calculate values, fetch data from APIs, update state, render lists, and manage application behavior.

1.1 Why Are Functions Important?

  • Code reusability: Write logic once and use it multiple times.
  • Modularity: Divide a large application into smaller, manageable parts.
  • Readability: Give meaningful names to operations and make code easier to understand.
  • Maintainability: Update logic in one place instead of modifying repeated code.
  • Event handling: Respond to user actions such as button presses and text input.
  • Asynchronous operations: Process API requests and other tasks that take time.
  • Component behavior: Define reusable logic inside React Native functional components.

1.2 Example Without a Function

const price1 = 100;
const tax1 = 10;
const total1 = price1 + tax1;

const price2 = 200;
const tax2 = 20;
const total2 = price2 + tax2;

console.log(total1);
console.log(total2);

The calculation is repeated for different values. If the calculation becomes more complex, repeating the same logic can make the program harder to maintain.

1.3 Example Using a Function

function calculateTotal(price, tax) {
  return price + tax;
}

console.log(calculateTotal(100, 10));
console.log(calculateTotal(200, 20));

The function can now be reused with different arguments. This approach reduces duplication and makes the program easier to maintain.

2. Learning Objectives

After completing this topic, learners should be able to:

  • Understand the purpose and structure of JavaScript functions.
  • Declare and call functions correctly.
  • Differentiate parameters from arguments.
  • Use return statements to produce results.
  • Understand function expressions and anonymous functions.
  • Create and use arrow functions.
  • Understand the differences between traditional functions and arrow functions.
  • Explain callback functions and higher-order functions.
  • Use callbacks with array methods such as map(), filter(), and forEach().
  • Handle React Native events with functions and callbacks.
  • Understand asynchronous callbacks and basic error handling.
  • Apply functions in a small React Native application.

3. Understanding Function Syntax

A standard JavaScript function declaration uses the function keyword, followed by a function name, parentheses, and a code block enclosed in curly braces.

3.1 Basic Syntax

function functionName(parameters) {
  // Code to execute
  return result;
}

Parts of a function:

  • function: Keyword used to declare a traditional function.
  • functionName: The name used to identify and call the function.
  • parameters: Variables that receive input values.
  • { }: The function body containing instructions.
  • return: An optional statement that sends a result back to the caller.

3.2 Creating and Calling a Function

function greetUser() {
  console.log("Welcome to React Native!");
}

greetUser();

Output:

Welcome to React Native!

Declaring a function does not automatically execute its body. The function must be called, as shown by greetUser().

3.3 Calling a Function Multiple Times

function showMessage() {
  console.log("Learning JavaScript functions");
}

showMessage();
showMessage();
showMessage();

The same function executes three times. Each call runs the statements inside its body.

3.4 Functions with Parameters

Parameters allow functions to receive values and work with different inputs.

function greet(name) {
  console.log("Hello, " + name);
}

greet("Aarav");
greet("Priya");

Output:

Hello, Aarav
Hello, Priya

Here, name is a parameter. The values "Aarav" and "Priya" are arguments passed to the function.

4. Parameters and Arguments

Parameters and arguments are related concepts, but they have different roles. Parameters are variables listed in a function definition. Arguments are the actual values supplied when calling that function.

4.1 Example

function multiply(a, b) {
  return a * b;
}

const result = multiply(5, 4);

console.log(result);

Output:

20
  • a and b are parameters.
  • 5 and 4 are arguments.
  • a * b is the calculation.
  • return sends the calculated value back to the caller.

4.2 Multiple Parameters

function calculateArea(length, width) {
  return length * width;
}

console.log(calculateArea(10, 5));
console.log(calculateArea(8, 3));

Output:

50
24

4.3 Default Parameters

Default parameters provide fallback values when an argument is omitted or explicitly supplied as undefined.

function greet(name = "Guest") {
  return `Welcome, ${name}!`;
}

console.log(greet("Riya"));
console.log(greet());

Output:

Welcome, Riya!
Welcome, Guest!

Default parameters are useful when an optional value has a sensible fallback.

4.4 Rest Parameters

Rest parameters allow a function to receive any number of arguments as an array.

function calculateSum(...numbers) {
  return numbers.reduce((total, number) => total + number, 0);
}

console.log(calculateSum(10, 20));
console.log(calculateSum(5, 10, 15, 20));

Output:

30
50

The rest parameter ...numbers collects all remaining arguments into an array. Rest parameters must be the final parameter in a function's parameter list.

5. Return Statements in Functions

The return statement ends the current function execution and optionally provides a value to the caller. A returned value can be stored in a variable, displayed in the interface, or passed to another function.

5.1 Function That Returns a Value

function add(a, b) {
  return a + b;
}

const result = add(10, 15);

console.log(result);

Output:

25

5.2 Function Without an Explicit Return Value

function showWelcome() {
  console.log("Welcome!");
}

const result = showWelcome();

console.log(result);

Output:

Welcome!
undefined

A function without an explicit return value returns undefined.

5.3 Returning Early

A function can return before reaching its final statement. This is useful for validation and handling invalid input.

function checkAge(age) {
  if (age < 18) {
    return "Not eligible";
  }

  return "Eligible";
}

console.log(checkAge(16));
console.log(checkAge(21));

Output:

Not eligible
Eligible

5.4 Important Difference Between return and console.log()

  • return sends a value back to the code that called the function.
  • console.log() prints a value in the development console.
  • A logged value is not automatically returned by the function.
function firstExample() {
  return 10;
}

function secondExample() {
  console.log(10);
}

const first = firstExample();
const second = secondExample();

console.log(first);  // 10
console.log(second); // undefined

6. Types of Functions in JavaScript

JavaScript supports several ways to define and use functions. The best choice depends on how the function needs to behave and how it will be used.

6.1 Function Declaration

function subtract(a, b) {
  return a - b;
}

console.log(subtract(10, 4));

Function declarations are generally initialized during the scope's instantiation process, so they can usually be called before their declaration appears in the code.

6.2 Function Expression

A function expression creates a function and assigns it to a variable.

const divide = function (a, b) {
  return a / b;
};

console.log(divide(20, 4));

Because this example uses const, the variable cannot be accessed before its declaration is initialized.

6.3 Anonymous Function

An anonymous function is a function without its own explicit name. Anonymous functions are often used in function expressions and callbacks.

const sayHello = function () {
  console.log("Hello!");
};

sayHello();

6.4 Named Function Expression

const factorial = function calculateFactorial(number) {
  if (number <= 1) {
    return 1;
  }

  return number * calculateFactorial(number - 1);
};

console.log(factorial(5));

The internal name calculateFactorial can be useful for recursion and debugging.

6.5 Immediately Invoked Function Expression (IIFE)

An IIFE is a function expression that executes immediately after it is defined.

(function () {
  console.log("This function runs immediately.");
})();

IIFEs are less common in modern React Native application code because modules, block scope, and functions declared within components often provide clearer alternatives.

6.6 Recursive Function

A recursive function calls itself to solve a problem. It needs a base case to prevent infinite recursion.

function countdown(number) {
  if (number <= 0) {
    console.log("Finished");
    return;
  }

  console.log(number);
  countdown(number - 1);
}

countdown(3);

Output:

3
2
1
Finished

7. Arrow Functions in JavaScript

Arrow functions provide a concise syntax for creating function expressions. They were introduced in ECMAScript 2015 (ES6) and are widely used in modern JavaScript and React Native projects.

An arrow function uses the => symbol, commonly called the arrow operator.

7.1 Basic Arrow Function Syntax

const functionName = (parameters) => {
  // Function body
  return result;
};

7.2 Traditional Function and Arrow Function Comparison

// Traditional function
function add(a, b) {
  return a + b;
}

// Arrow function
const addArrow = (a, b) => {
  return a + b;
};

console.log(add(5, 3));
console.log(addArrow(5, 3));

Both functions return the sum of their two arguments.

7.3 Arrow Function with One Parameter

Parentheses around a single parameter can be omitted, although keeping them is also valid.

const square = number => {
  return number * number;
};

console.log(square(6));

Output:

36

7.4 Arrow Function with No Parameters

When there are no parameters, empty parentheses are required.

const showMessage = () => {
  console.log("Hello from React Native!");
};

showMessage();

7.5 Implicit Return

If an arrow function contains a single expression, the expression's value can be returned without writing the return keyword or a function body.

const add = (a, b) => a + b;

const double = number => number * 2;

console.log(add(10, 20));
console.log(double(7));

Output:

30
14

7.6 Returning an Object from an Arrow Function

When implicitly returning an object literal, wrap the object in parentheses. Otherwise, the curly braces may be interpreted as the function body.

const createUser = (name, age) => ({
  name: name,
  age: age
});

console.log(createUser("Aman", 25));

Output:

{ name: 'Aman', age: 25 }

7.7 Multiline Arrow Function

Use curly braces when the function needs multiple statements. Include an explicit return statement when a value must be returned.

const calculateDiscount = (price, percentage) => {
  const discount = price * percentage / 100;
  const finalPrice = price - discount;

  return finalPrice;
};

console.log(calculateDiscount(1000, 10));

Output:

900

8. Traditional Functions vs Arrow Functions

Feature Traditional Function Arrow Function
Syntax Uses the function keyword Uses the => operator
Length Can require more code Often more concise
Own this Depends on how the function is called Uses this from its surrounding lexical scope
Own arguments object Available in ordinary non-arrow functions Not available as its own arguments object
Constructor Some traditional functions can be called with new Cannot be used as constructors
Implicit return Not supported in ordinary function bodies Supported for concise expression bodies
Common usage Named utilities, methods, constructors, and special cases Callbacks, concise utilities, and React event handlers

8.1 Understanding this in Traditional Functions

In an ordinary function, the value of this depends on how the function is called. For example, a method call usually binds this to the object before the dot.

const user = {
  name: "Rohan",
  greet: function () {
    return `Hello, ${this.name}`;
  }
};

console.log(user.greet());

Output:

Hello, Rohan

8.2 Understanding Lexical this in Arrow Functions

Arrow functions do not create their own this. They use the value from the surrounding lexical scope. This is useful in many callbacks, but an arrow function should not be used when a method needs its own dynamically determined this.

const user = {
  name: "Rohan",
  greet() {
    return () => {
      return `Hello, ${this.name}`;
    };
  }
};

const greeting = user.greet();

console.log(greeting());

Output:

Hello, Rohan

8.3 When Should You Use Arrow Functions?

  • For short calculations and utility functions.
  • For callbacks passed to array methods.
  • For event handlers in React Native components.
  • For callbacks that should retain the surrounding lexical this.
  • For inline functions where concise syntax improves readability.

8.4 When Might a Traditional Function Be Better?

  • When you need a function's own this behavior.
  • When defining a constructor function that supports new.
  • When you need an ordinary function's own arguments object.
  • When a named function declaration improves clarity or supports calling the function before its declaration.

9. Scope and Closures in Functions

Scope determines where a variable can be accessed. Understanding scope is important when working with callbacks, event handlers, and React Native state.

9.1 Global Scope

A variable declared at the top level of a module can generally be accessed by functions defined within that module, subject to the module's scope.

const appName = "My React Native App";

function showAppName() {
  console.log(appName);
}

showAppName();

9.2 Function Scope

Variables declared with let or const inside a function are accessible within that function and its nested scopes, but not from outside the function.

function displayMessage() {
  const message = "Hello!";
  console.log(message);
}

displayMessage();

// console.log(message); // ReferenceError

9.3 Block Scope

Variables declared using let and const are limited to the block in which they are declared.

if (true) {
  const status = "Active";
  console.log(status);
}

// console.log(status); // ReferenceError

9.4 Lexical Scope and Closures

A nested function can access variables from the scope where it was created. When a function retains access to its surrounding lexical environment after the outer function has finished, this is called a closure.

function createCounter() {
  let count = 0;

  return function () {
    count += 1;
    return count;
  };
}

const counter = createCounter();

console.log(counter());
console.log(counter());
console.log(counter());

Output:

1
2
3

Closures are useful for preserving values between function calls. In React, callbacks can capture values from the render in which they were created, so developers should understand how state and dependencies affect callback behavior.

10. Callback Functions

A callback is a function passed to another function as an argument so that the receiving function can invoke it. Callbacks allow developers to customize what happens after an operation, when an event occurs, or while processing data.

Callbacks are commonly used in JavaScript array methods, React Native event handlers, timers, and asynchronous operations.

10.1 Basic Callback Example

function greet(name, callback) {
  console.log("Hello, " + name);
  callback();
}

function showMessage() {
  console.log("Welcome to JavaScript!");
}

greet("Aarav", showMessage);

Output:

Hello, Aarav
Welcome to JavaScript!

The function showMessage is passed as a value, without parentheses. The receiving function calls it using callback().

10.2 Passing an Anonymous Function as a Callback

function processTask(callback) {
  console.log("Processing task...");

  callback();
}

processTask(function () {
  console.log("Task completed.");
});

10.3 Passing an Arrow Function as a Callback

function calculate(a, b, callback) {
  return callback(a, b);
}

const result = calculate(10, 5, (x, y) => x + y);

console.log(result);

Output:

15

10.4 Callback with Parameters

function sendNotification(message, callback) {
  console.log("Notification: " + message);
  callback(message);
}

sendNotification("Your order has shipped.", message => {
  console.log("Logged message: " + message);
});

The receiving function can pass data to the callback when it invokes it.

10.5 Why Are Callbacks Useful?

  • They allow one function to define what happens after another operation.
  • They support reusable and configurable behavior.
  • They help process items in arrays.
  • They are used to handle UI events in React Native.
  • They can respond to the completion of asynchronous work.
  • They allow functions to communicate results without hardcoding every possible action.

11. Synchronous and Asynchronous Callbacks

11.1 Synchronous Callback

A synchronous callback executes during the current operation, before that operation finishes returning control to its caller.

function calculate(number, callback) {
  const result = number * 2;
  callback(result);
}

calculate(5, result => {
  console.log("Result:", result);
});

console.log("Finished");

Output:

Result: 10
Finished

11.2 Asynchronous Callback

An asynchronous callback executes later, after a timer, event, or other asynchronous operation reaches the appropriate point.

console.log("Start");

setTimeout(() => {
  console.log("Timer callback executed");
}, 1000);

console.log("End");

The typical output order is:

Start
End
Timer callback executed

The timer schedules the callback to run later. The main JavaScript execution continues without waiting for the timer to finish.

11.3 Callback Timing Matters

A callback does not automatically mean that an operation is asynchronous. The function receiving the callback decides when and how often to invoke it. Array methods such as map() normally invoke their callbacks synchronously, while event handlers and timers may execute at a later time.

12. Callback Functions with Array Methods

JavaScript array methods accept callback functions to process array items. These methods are frequently used to display lists, transform data received from APIs, and filter information in React Native applications.

12.1 map()

The map() method creates a new array by applying a callback to each element of the original array.

const numbers = [1, 2, 3, 4];

const doubled = numbers.map(number => number * 2);

console.log(doubled);

Output:

[2, 4, 6, 8]

Use map() when you want to transform every item into a corresponding value.

12.2 filter()

The filter() method creates a new array containing the elements for which the callback returns a truthy value.

const numbers = [10, 15, 20, 25, 30];

const filtered = numbers.filter(number => number > 20);

console.log(filtered);

Output:

[25, 30]

12.3 forEach()

The forEach() method calls a callback for each array element. It is useful when you need to perform an action for every item and do not need a new array returned by the method.

const names = ["Aarav", "Priya", "Rohan"];

names.forEach(name => {
  console.log(name);
});

Output:

Aarav
Priya
Rohan

forEach() returns undefined, so it should not be used when you need the transformed array.

12.4 find()

The find() method returns the first element for which the callback returns a truthy value. If no element matches, it returns undefined.

const users = [
  { id: 1, name: "Aarav" },
  { id: 2, name: "Priya" },
  { id: 3, name: "Rohan" }
];

const user = users.find(item => item.id === 2);

console.log(user);

Output:

{ id: 2, name: 'Priya' }

12.5 reduce()

The reduce() method processes array elements to produce a single accumulated result, such as a sum or total price.

const prices = [100, 200, 300];

const total = prices.reduce((sum, price) => {
  return sum + price;
}, 0);

console.log(total);

Output:

600

12.6 Array Methods Comparison

Method Purpose Typical Result
map() Transform each element New array
filter() Select matching elements New array
forEach() Perform an action for each element undefined
find() Find the first matching element Element or undefined
reduce() Accumulate a result Single accumulated value

13. Higher-Order Functions

A higher-order function is a function that accepts another function as an argument, returns a function, or does both. Callback-based functions are often examples of higher-order functions.

13.1 Accepting a Function as an Argument

function performOperation(a, b, operation) {
  return operation(a, b);
}

const addition = (a, b) => a + b;
const multiplication = (a, b) => a * b;

console.log(performOperation(4, 3, addition));
console.log(performOperation(4, 3, multiplication));

Output:

7
12

13.2 Returning a Function

function createMultiplier(multiplier) {
  return function (number) {
    return number * multiplier;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5));
console.log(triple(5));

Output:

10
15

Higher-order functions help separate the operation from the data or context in which it is used.

14. Functions in React Native

React Native applications use functions to define component behavior, respond to user interactions, transform data, and perform application tasks. Functional components are ordinary JavaScript functions that return React elements, commonly written using JSX.

14.1 A Simple Functional Component

import React from "react";
import { View, Text } from "react-native";

export default function WelcomeScreen() {
  return (
    <View>
      <Text>Welcome to React Native!</Text>
    </View>
  );
}

WelcomeScreen is a function component. When React renders it, the returned JSX describes the interface.

14.2 Using a Helper Function in a Component

import React from "react";
import { View, Text } from "react-native";

function formatWelcome(name) {
  return `Welcome, ${name}!`;
}

export default function WelcomeScreen() {
  return (
    <View>
      <Text>{formatWelcome("Aarav")}</Text>
    </View>
  );
}

The helper function returns text that the component displays inside a Text component.

15. Event Handling and Callback Functions in React Native

React Native components provide event props such as onPress for pressable controls. These props generally expect a function that React Native can call when the event occurs.

15.1 Handling a Button Press

import React from "react";
import { View, Button, Alert } from "react-native";

export default function App() {
  function handlePress() {
    Alert.alert("Success", "The button was pressed!");
  }

  return (
    <View>
      <Button
        title="Press Me"
        onPress={handlePress}
      />
    </View>
  );
}

In this example, handlePress is passed as a callback. React Native invokes it when the user presses the button.

15.2 Using an Arrow Function as an Event Handler

import React from "react";
import { View, Button, Alert } from "react-native";

export default function App() {
  return (
    <View>
      <Button
        title="Show Message"
        onPress={() => Alert.alert("Hello", "Welcome!")}
      />
    </View>
  );
}

An inline arrow function is useful for a short event handler. For more complex behavior, a separately named function can improve readability.

15.3 Passing Arguments to Event Handlers

If an event handler needs an argument, use a wrapper function so the action runs when the event occurs, rather than immediately during rendering.

import React from "react";
import { View, Button, Alert } from "react-native";

export default function App() {
  function showUser(name) {
    Alert.alert("Selected User", name);
  }

  return (
    <View>
      <Button
        title="Select Aarav"
        onPress={() => showUser("Aarav")}
      />
      <Button
        title="Select Priya"
        onPress={() => showUser("Priya")}
      />
    </View>
  );
}

The arrow function acts as a wrapper callback and supplies the selected name when the button is pressed.

15.4 Incorrect Event Handler Assignment

// Incorrect for an event handler:
<Button title="Press Me" onPress={handlePress()} />

// Correct:
<Button title="Press Me" onPress={handlePress} />

// Also correct when arguments are needed:
<Button title="Press Me" onPress={() => handlePress("Aarav")} />

The incorrect example calls handlePress() during rendering and passes its return value instead of passing the function itself. Event handlers should normally receive a function reference.

16. Functions with React State

React's useState hook allows a functional component to store and update state. State setter functions can accept either a new value or an updater callback. An updater callback receives the previous state and calculates the next state.

16.1 Updating a Counter

import React, { useState } from "react";
import { View, Text, Button } from "react-native";

export default function CounterApp() {
  const [count, setCount] = useState(0);

  function increaseCount() {
    setCount(previousCount => previousCount + 1);
  }

  return (
    <View>
      <Text>Count: {count}</Text>
      <Button title="Increase" onPress={increaseCount} />
    </View>
  );
}

The callback previousCount => previousCount + 1 calculates the next state from the previous state. This approach is useful when the next value depends on the previous value.

16.2 Decreasing a Counter

function decreaseCount() {
  setCount(previousCount => previousCount - 1);
}

For a complete component, define decreaseCount inside the component where setCount is available, and pass it to the appropriate event prop.

16.3 Toggle State

function toggleStatus() {
  setIsActive(previousStatus => !previousStatus);
}

This updater callback calculates the next Boolean state from the previous state.

16.4 Avoid Mutating State Directly

// Avoid changing state variables directly.
items.push(newItem);

// Prefer creating a new array.
setItems(previousItems => [...previousItems, newItem]);

When updating arrays or objects in React state, create a new value rather than modifying the existing state value directly.

17. Callback Functions for Lists in React Native

List screens frequently need callbacks to transform, filter, or render data. JavaScript array methods are useful for preparing data, while React Native's FlatList supports efficient rendering of longer lists.

17.1 Rendering a List with map()

import React from "react";
import { View, Text } from "react-native";

export default function NameList() {
  const names = ["Aarav", "Priya", "Rohan"];

  return (
    <View>
      {names.map(name => (
        <Text key={name}>{name}</Text>
      ))}
    </View>
  );
}

The callback passed to map() returns a Text element for each name. Each rendered item should have a stable, unique key. If names are not unique, use a unique identifier from the data.

17.2 Rendering Data with FlatList

import React from "react";
import { FlatList, Text } from "react-native";

const users = [
  { id: "1", name: "Aarav" },
  { id: "2", name: "Priya" },
  { id: "3", name: "Rohan" }
];

export default function UserList() {
  return (
    <FlatList
      data={users}
      keyExtractor={item => item.id}
      renderItem={({ item }) => (
        <Text>{item.name}</Text>
      )}
    />
  );
}

The keyExtractor callback returns a stable key for each item. The renderItem callback describes how each item should appear.

17.3 Filtering List Data

const activeUsers = users.filter(user => user.active);

This expression returns a new array containing only users whose active property is truthy. Ensure that the data objects actually contain the property used in the filter.

18. Asynchronous Functions and Callbacks

React Native applications often need to retrieve information from servers or perform operations that complete later. JavaScript supports callbacks, promises, and async/await for handling asynchronous work.

18.1 Callback with setTimeout()

function showDelayedMessage(callback) {
  setTimeout(() => {
    callback("Data received!");
  }, 1000);
}

showDelayedMessage(message => {
  console.log(message);
});

The callback receives the message after the timer completes.

18.2 Using Promises

function fetchMessage() {
  return new Promise((resolve, reject) => {
    const success = true;

    if (success) {
      resolve("Operation completed");
    } else {
      reject(new Error("Operation failed"));
    }
  });
}

fetchMessage()
  .then(message => console.log(message))
  .catch(error => console.error(error.message));

A promise represents the eventual completion or failure of an asynchronous operation. The then() and catch() methods accept callbacks for handling success and failure.

18.3 Using async and await

async function loadMessage() {
  try {
    const message = await fetchMessage();
    console.log(message);
  } catch (error) {
    console.error(error.message);
  }
}

loadMessage();

The async keyword makes a function return a promise. The await keyword pauses that async function until the awaited promise settles, without blocking the entire JavaScript thread.

18.4 Fetching Data in a React Native App

async function loadUsers() {
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");

    if (!response.ok) {
      throw new Error("Failed to load users");
    }

    const users = await response.json();
    return users;
  } catch (error) {
    console.error("Error loading users:", error.message);
    throw error;
  }
}

This function requests user data, checks the HTTP response status, parses the JSON response, and returns the data. The calling code should handle the returned promise and display loading, success, or error states as appropriate.

19. Common Mistakes When Using Functions and Callbacks

19.1 Calling a Function Instead of Passing It

// Incorrect:
buttonHandler()

// Pass the function reference:
buttonHandler

In event props such as onPress, passing the function reference allows React Native to call it when the event occurs. Calling the function immediately is appropriate only when immediate execution is intended.

19.2 Forgetting to Return a Value

const calculate = (a, b) => {
  a + b;
};

console.log(calculate(2, 3)); // undefined

To return the result, use return a + b; inside the block or use the concise expression form const calculate = (a, b) => a + b;.

19.3 Confusing map() and forEach()

const numbers = [1, 2, 3];

const doubled = numbers.map(number => number * 2);
const result = numbers.forEach(number => number * 2);

console.log(doubled); // [2, 4, 6]
console.log(result);  // undefined

Use map() when you need a transformed array. Use forEach() when you need to perform an action for each item.

19.4 Using an Arrow Function with the Wrong Return Syntax

// Incorrect if an object is intended:
const createUser = name => { name: name };

// Correct:
const createUser = name => ({ name: name });

Wrap an object literal in parentheses when returning it implicitly from an arrow function.

19.5 Forgetting Error Handling

async function loadData() {
  try {
    const response = await fetch("https://example.com/data");

    if (!response.ok) {
      throw new Error("Request failed");
    }

    return await response.json();
  } catch (error) {
    console.error(error.message);
    throw error;
  }
}

In production applications, handle failed requests and show an appropriate message to users rather than relying only on console output.

19.6 Using Stale State in Callbacks

A callback created during a render can capture values from that render. When updating state based on the previous state, use the functional updater form when appropriate.

setCount(previousCount => previousCount + 1);

For effects and long-lived callbacks, review the relevant dependencies and how values are captured. Do not assume every callback automatically receives the latest value of every variable.

20. Best Practices for Functions in React Native

  • Use meaningful function names such as handleSubmit, calculateTotal, and loadUsers.
  • Keep functions focused on one clear responsibility.
  • Prefer reusable helper functions when the same logic is needed in several places.
  • Use arrow functions where their concise syntax and lexical behavior are suitable.
  • Use named functions when they improve readability and debugging.
  • Pass function references to event props instead of calling handlers during rendering.
  • Use wrapper callbacks when an event handler needs specific arguments.
  • Return values when the caller needs to use the result.
  • Use map() for transformations and filter() for selection.
  • Use functional state updates when the next state depends on the previous state.
  • Handle rejected promises and failed HTTP responses.
  • Avoid mutating arrays and objects stored in React state.
  • Use stable keys when rendering collections of elements.
  • Keep inline callbacks simple; extract complicated logic into named functions.
  • Use useCallback only when there is a practical reason to preserve a function reference, such as a memoized child or a dependency requirement. It is not automatically necessary for every handler.
  • Test important functions with typical, boundary, and invalid inputs.

21. Practical Exercise 1: Calculator Functions

Objective: Create reusable functions for basic mathematical operations.

const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
const multiply = (a, b) => a * b;

const divide = (a, b) => {
  if (b === 0) {
    return "Cannot divide by zero";
  }

  return a / b;
};

console.log(add(10, 5));
console.log(subtract(10, 5));
console.log(multiply(10, 5));
console.log(divide(10, 5));
console.log(divide(10, 0));

Expected output:

15
5
50
2
Cannot divide by zero

Practice task: Add a function that calculates the remainder and another that calculates a percentage.

22. Practical Exercise 2: Callback-Based Calculator

Objective: Pass a function as an argument to perform different calculations.

function calculate(a, b, callback) {
  return callback(a, b);
}

const add = (a, b) => a + b;
const multiply = (a, b) => a * b;
const subtract = (a, b) => a - b;

console.log(calculate(8, 2, add));
console.log(calculate(8, 2, multiply));
console.log(calculate(8, 2, subtract));

Expected output:

10
16
6

Practice task: Add division with validation and pass it as another callback.

23. Practical Exercise 3: React Native Counter App

Objective: Use functions, arrow functions, event callbacks, and state updater callbacks to build a simple counter.

import React, { useState } from "react";
import { View, Text, Button, StyleSheet } from "react-native";

export default function CounterApp() {
  const [count, setCount] = useState(0);

  const increase = () => {
    setCount(previousCount => previousCount + 1);
  };

  const decrease = () => {
    setCount(previousCount => previousCount - 1);
  };

  const reset = () => {
    setCount(0);
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Counter App</Text>
      <Text style={styles.count}>Count: {count}</Text>
      <Button title="Increase" onPress={increase} />
      <Button title="Decrease" onPress={decrease} />
      <Button title="Reset" onPress={reset} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    padding: 20,
    gap: 12
  },
  title: {
    fontSize: 24,
    textAlign: "center",
    fontWeight: "bold"
  },
  count: {
    fontSize: 20,
    textAlign: "center"
  }
});

What this project demonstrates:

  • CounterApp is a functional component.
  • increase, decrease, and reset are event handler functions.
  • The onPress props receive function references.
  • The updater callbacks calculate new values from the previous state.
  • The interface updates when the counter state changes.

24. Practical Exercise 4: User List and Filtering

Objective: Use arrow functions, filter(), and map() to display a filtered list.

import React from "react";
import { View, Text } from "react-native";

const users = [
  { id: "1", name: "Aarav", active: true },
  { id: "2", name: "Priya", active: false },
  { id: "3", name: "Rohan", active: true }
];

export default function ActiveUserList() {
  const activeUsers = users.filter(user => user.active);

  return (
    <View>
      <Text>Active Users</Text>
      {activeUsers.map(user => (
        <Text key={user.id}>{user.name}</Text>
      ))}
    </View>
  );
}

Expected result: The screen displays Aarav and Rohan because their active property is true.

25. Interview Questions and Answers

Q1. What is a function in JavaScript?

A function is a reusable block of code that performs a task. It can accept input through parameters and optionally return a result.

Q2. What is the difference between a parameter and an argument?

A parameter is a variable listed in a function definition. An argument is a value supplied when the function is called.

Q3. What is an arrow function?

An arrow function is a function expression that uses the => syntax. It provides concise syntax and inherits this from its surrounding lexical scope.

Q4. What is an implicit return?

An implicit return occurs when a concise arrow function returns the result of an expression without using an explicit return statement.

Q5. What is a callback function?

A callback is a function passed to another function so that the receiving function can invoke it at the appropriate time.

Q6. What is a higher-order function?

A higher-order function accepts a function as an argument, returns a function, or both.

Q7. What is the difference between map() and forEach()?

map() creates a new array from callback results. forEach() executes a callback for each element and returns undefined.

Q8. Why do React Native event handlers use callbacks?

Callbacks allow React Native to invoke application logic in response to events, such as a user pressing a button.

Q9. Why should you avoid calling an event handler during rendering?

Calling a handler during rendering executes it immediately rather than waiting for the event. Passing the function reference or using a wrapper callback avoids this problem.

Q10. Can arrow functions be used as constructors?

No. Arrow functions cannot be used with new because they do not have the constructor behavior of ordinary constructible functions.

Q11. What does a function return if there is no return statement?

It returns undefined.

Q12. What is a closure?

A closure is a function that retains access to variables from its surrounding lexical environment, even after the outer function has finished executing.

Q13. What is the purpose of a functional state updater?

A functional state updater receives the previous state and calculates the next state. It is useful when the new state depends on the previous value.

Q14. What is the difference between synchronous and asynchronous callbacks?

A synchronous callback executes during the current operation. An asynchronous callback is scheduled to execute later, such as after a timer or an event.

Q15. When should useCallback be considered in React?

useCallback can preserve a function reference between renders when that is useful for memoized children or hook dependencies. It should be applied when there is a practical benefit, not automatically to every function.

26. Quick Revision Checklist

  • Understand function declarations and function expressions.
  • Know the difference between parameters and arguments.
  • Understand how return statements work.
  • Recognize default and rest parameters.
  • Create arrow functions with zero, one, or multiple parameters.
  • Understand implicit returns and object return syntax.
  • Know how traditional functions differ from arrow functions.
  • Understand scope, lexical scope, and closures.
  • Explain callback functions and higher-order functions.
  • Use callbacks with map(), filter(), forEach(), find(), and reduce().
  • Pass functions to React Native event props such as onPress.
  • Use functional state updates when the next value depends on the previous state.
  • Understand basic asynchronous callbacks, promises, and async/await.
  • Handle errors and avoid common function-related mistakes.

27. Recommended Learning Resources

28. Conclusion

Functions, arrow functions, and callback functions are fundamental building blocks of JavaScript and React Native development. Functions organize reusable logic, arrow functions offer concise syntax and lexical this behavior, and callbacks allow one function to provide behavior to another.

These concepts are used throughout React Native applications, including button event handlers, state updates, list rendering, data transformations, and asynchronous requests. Practising the examples and exercises in these notes will help learners write cleaner, more reusable, and easier-to-maintain mobile application code.

For more information about React Native training, visit React Native Training at JustAcademy or register through the course demo registration page.

whatsapp