You get to decide whether a function is a React function, a custom function, or a regular function, which defines who can call it from where. If F1 is a React function (functional component) you can call it as <F1 /> but should not call it as F1(); if F1 is a regular function you can call it as F1() but should not call it as <F1 />. The naming convention (F1, f1, or useF1) would help you distinguish which type of function you intend, which helps you and the linter hold to those rules; things might work if you break the rules, but they also might fail in difficult-to-debug ways.
- React function (functional component): Call from
createElement or JSX. Can call hooks according to the rules and should return createElement or JSX expressions. Named with upper camel case (Foo) by convention.
- Custom hook: Call from functional components or other custom hooks. Can call hooks according to the rules; can return anything. Named with lower camel case starting with "use" (
useFoo) by convention.
- Regular function: Call from anywhere. Shouldn't call hooks; can return anything. Named with lower camel case (
foo) as usual.
In addition to Nicholas Tower's answer, you should observe that <F1 /> and F1() are not identical. From the "JSX Represents Objects" header of React's Main Concepts / Introducing JSX:
Babel compiles JSX down to React.createElement() calls.
These two examples are identical:
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
Specifically, this example:
function F1() {
return <F1>hello</F1>;
}
function F2() {
}
compiles to this JS:
"use strict";
function F1() {
return /*#__PURE__*/React.createElement(F1, null, "hello");
}
function F2() {}
F1 doesn't call F2, F1 passes F2 to React.createElement(). Consequently, createElement gets to call F2 exactly and only when it is ready to do so, allowing it to create a fresh internal state (i.e. history of hook calls). So when you define F2 like this:
// React function, returns JSX
function F2() {
useState('Mary') // 1. Initialize the name state variable with 'Mary'
useEffect(persistForm) // 2. Add an effect for persisting the form
useState('Poppins') // 3. Initialize the surname state variable with 'Poppins'
useEffect(updateTitle) // 4. Add an effect for updating the title
useLogin() // 5 & 6
}
// Custom hook, can call hooks according to rules, named "use" by convention
function useLogin() {
const [user, setUser] = useState(getDefaultUser());
const [domain, setDomain] = useState(getDomain());
}
// Normal function, can't call hooks
function getDefaultUser() {
return "defaultUser";
}
...then React can generate a new hook state for that particular component invocation, call F2 itself, and then wind up with an internal state that looks like [useState, useEffect, useState, useEffect, useState(useLogin:user), useState(useLogin:domain)]. Because of the rules for hooks barring conditionals and loops, if you've done it right, every invocation of F2 will wind up with exactly those six entries. If you use hooks from a "regular Javascript function" like getDefaultUser(), it might work by accident, but it will be harder to understand the usage and hold to the rules.
Thus, you are the one that determines which type of function a function is, all in service of keeping that state predictable.