2

This is not for behavior but syntax.

The syntax is the same for both, I can very well create a random function that takes an argument named props, but will React take it and do its virtual DOM thing with that function? OR it might be checking if that function is returning JSX , but when does this check happen ?

As react is just a library when does this static differentiation of which function is a component and which is not happen?

Any reference to documentation will help.

isherwood
  • 58,414
  • 16
  • 114
  • 157
ashish singh
  • 6,526
  • 2
  • 15
  • 35
  • While I do not address your question specifically, the information in [my answer about defining components inside components](https://stackoverflow.com/a/59636503/1218980) have some insightful information on some of the different function types we see used in React. – Emile Bergeron Jan 18 '22 at 06:15
  • There's also this one: [What's the difference between functions that render JSX vs. declaring components inside another component?](https://stackoverflow.com/q/67454966/1218980) – Emile Bergeron Jan 18 '22 at 06:19
  • 1
    The gist of it is: A function can be designed to be used as a component, but not every function returning JSX is necessarily (meant to be) a component. – Emile Bergeron Jan 18 '22 at 06:20
  • 2
    React does not decide which function to use as a component, you explicitly use it as a component(like ``) and then react renders it. If your function does not follow the design for a functional component, it will not work and will display errors. – AKT Jan 18 '22 at 06:23
  • 1
    The differentiation happens when you decide to use the function as a component by calling it within JSX: `` which is equivalent to `React.createElement(MyFunction)` regardless of its parameters. – Emile Bergeron Jan 18 '22 at 06:24
  • There's no difference, a *function* component is a function. (Notice that the term is not "functional") – Bergi Jan 19 '22 at 20:24

1 Answers1

1

React does not do any static analysis to determine if a function is a component.

Instead, React will do "it's virtual DOM thing" (and all the other magic like lifecycles) if the function returns a valid React element.

React throws an error if the function doesn't return a React element.

https://reactjs.org/docs/components-and-props.html:

This function is a valid React component because it accepts a single “props” (which stands for properties) object argument with data and returns a React element. We call such components “function components” because they are literally JavaScript functions.

In more detail ...

Technically React doesn't need any functional or class components at all.

Using functions

Consider this example, without any components or functions:

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  React.createElement( 'div', null, [
      React.createElement( 'h1', null, 'React without any functions' ),
      React.createElement( 'p', null, 'Technically you don\'t need to pass functions to React.' ),
  ]),
  document.getElementById('root')
);

This quickly becomes cumbersome.

So one might have the idea to separate the code into "parts" by using functions which return these parts instead, e.g.:

const Headline = function(){
  return React.createElement( 'h1', null, 'React with "factory functions"' );
};

const Content = function(){
  return React.createElement( 'p', null, 'You might want to separate stuff using functions.' );
};

const Page = function(){
  return React.createElement( 'div', null, [
    Headline(),
    Content()
  ]);
};

ReactDOM.render(
  Page(),
  document.getElementById('root')
);

Note that these are just normal javascript functions, no "magic" at all.

If your function doesn't return a valid ReactElement, then React just throws an error, e.g.:

const Page = function(){
  return { notAValidReactElement: 'this is not a valid react element' };
};

ReactDOM.render(
  Page(),  // ---> Uncaught Error: Objects are not valid as a React child ...
  document.getElementById('root')
);

React "component" type

But this is not optimal, e.g. all .createElement() methods are still always executed at the same time.

The React people had similar ideas, so React accepts a function name as type parameter (instead of e.g. 'h1'), and uses that function like a callback, so that React can decide e.g. if the function actually needs to be executed, or can be skipped:

const Page = function(){
  return React.createElement( 'div', null, [
    React.createElement( Headline, null, [] ),
    React.createElement( Content, null, [] ) 
  ]);
}

These are still the same functions as before. They just work because we wrote them so that they return a correct value.

This is actually more or less the full story regarding this topic, but people might also be confused why I am talking about React.createElement( Page, ..., while we are normally using something like <Page>....

So ...

JSX

One might have the idea to shorten the React.createElement a bit, for less typing, e.g.:

const CE = function( type, props, childs ){
  return React.createElement( type, props, childs );
};

ReactDOM.render(
  CE( 'div', null, [
      CE( 'h1', null, 'React without any functions' ),
      CE( 'p', null, [
      CE('b', null, 'Nice'),
      ' if we can shorten the code a bit.',
    ] ),
  ]),
  document.getElementById('root')
);

Luckily smart people have had this idea already, so you can use JSX instead, e.g.:

ReactDOM.render(
  <div>
    <h1>React without any functions</h1>
      <p>
      <b>Even nicer: </b>
      we can just use JSX!
    </p>
  </div>,
  document.getElementById('root')
);

That's just a different syntax, that gets converted into javascript at build time.

(Maybe also have a look at Hyperscript for comparison and background understanding.)

kca
  • 4,856
  • 1
  • 20
  • 41
  • 2
    _"React does not do any static analysis to determine if a function is a component"_ that's not completely true. Components must start with a capital letter (i.e., the function name) because it treats components starting with lowercase letters as DOM tags ([reference](https://reactjs.org/docs/components-and-props.html#rendering-a-component)) – Rafael Tavares Jan 19 '22 at 19:47
  • 2
    Good point. Good to mention that here. But [that uppercase requirement is JSX](https://reactjs.org/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized) interpreted at build time. For React it will work to use a lower case function in `.createElement( myFunction )` (unless you have some extra code analysis tools installed). – kca Jan 19 '22 at 20:02
  • I didn't know that, as I don't use `createElement`. But it's nice to know. – Rafael Tavares Jan 19 '22 at 20:04
  • 2
    "*This is actually more or less the full story regarding this topic*" - the important part you forgot is that function *components* that are rendered as an element, not just called as a function, do have a lifecycle. React does keep some global state that allows you to use hooks like `useState`, `useRef` or `useEffect` while rendering a function component. – Bergi Jan 19 '22 at 20:24
  • You are right. I just couldn't think of a way to integrate that and keep the answer "short". I still think this is not the place to explain that in depth, but maybe I should integrate a hint about that somewhere... will see if I get an Idea how to do that. – kca Jan 20 '22 at 09:39