React Learning (4) - Deep Explanation of JSX and props

Keywords: React Javascript Attribute

JSX Description

JSX can be understood as the grammatical sugar of the React. createElement (component, props,... Children) method. JSX code:

<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>

Eventually it will be compiled into a React Element object:

React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)

We can use the "closed label" to indicate the absence of child elements:

<div className="sidebar" />

It will compile into:

React.createElement(
  'div',
  {className: 'sidebar'},
  null
)

If you want to try out how various JSX can be converted into JavaScript code, you can open this website and try: the online Babel compiler.

Scope of React components

The first part of the JSX tag declaration is the Type of the React element. Capital letters indicate that the JSX tag is a component of React. These tags are compiled into direct references to named variables, so if you use JSX's < Foo /> expression, the Foo method or object must be included in the current domain (which can be understood to be found in the current page or closure).

import React from 'react';
import Foo from './Foo'; //ES6 import syntax, which must now be introduced into closures, can be used

Scope of React

Because JSX needs to call React.createElement for compilation, when using JSX expressions, React should always be referenced to the current domain (which can be understood as page or closure accessible to React.createElement).

As an example of the following code, even if the React.createElement method is not shown, React and components must be introduced when using any React build:

import React from 'react';
import CustomButton from './CustomButton';

function WarningButton() {
  // return React.createElement(CustomButton, {color: 'red'}, null);
  return <CustomButton color="red" />;
}

Use the dot "." to refer to components

In JSX grammar, you can use dots to introduce React components. The advantage of this is that if there are many React components in a module, we can easily categorize them. For example, MyComponents.DatePicker is a component that we can use directly in JSX syntax:

import React from 'react';

const MyComponents = {
  DatePicker: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
  }
}

function BlueDatePicker() {
  return <MyComponents.DatePicker color="blue" />;
}

User-defined component initials must be capitalized

When an element begins with a lowercase letter, it is recognized as a built-in component, such as < div > or < span > which will be translated into strings of'div','span'passed to the React.createElement method and eventually executed React.createElement('div'). If you start with a capital letter, such as < Foo />, it is translated into an object and passed as a parameter. The final method of execution is React.createElement(Foo).

We recommend capitalizing the initials when naming custom components. If you have to set the initials of a custom component to lowercase letters, assign them to uppercase variables before using JSX.

The following code will not be executed as expected:

import React from 'react';

// Error! Custom component initials capitalized
function hello(props) {
  // Correct! <div> is an HTML tag
  return <div>Hello {props.toWhat}</div>;
}

function HelloWorld() {
  // Error! Because the initials are not capitalized, React considers <hello> to be an HTML tag:
  return <hello toWhat="World" />;
}

We must amend it to read:

import React from 'react';

function Hello(props) {
  return <div>Hello {props.toWhat}</div>;
}

function HelloWorld() {
  return <Hello toWhat="World" />;
}

Type determination at runtime

Because of the language characteristics of JavaScript, we can determine the type at runtime. But we can't apply this general experience to JSX expressions. However, we can determine "runtime type" beyond JSX expressions by assigning JSX expressions to a capitalized variable. Example:

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
  photo: PhotoStory,
  video: VideoStory
};

function Story(props) {
  // Runtime error! JSX does not support such expressions.
  return <components[props.storyType] story={props.story} />;
}

The adjustment is as follows:

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
  photo: PhotoStory,
  video: VideoStory
};

function Story(props) {
  // Use a capitalized variable to point to the component declared by JSX.
  const SpecificStory = components[props.storyType];
  return <SpecificStory story={props.story} />;
}

This applies to scenarios where we decide to use a component based on certain conditions.

Passing JSX parameters using Prop

JavaScript expressions

Any JavaScript expression can be passed as a props parameter, and nested expressions in JSX are wrapped in {}. For example:

<MyComponent foo={1 + 2 + 3 + 4} />

The final parameter passed in by the MyComponent component is props.foo = 10, because the expression "1 + 2 + 3 + 4" has been computed before the parameter is passed in.

You can't use loop expressions such as for in {} of JSX. You can loop and traverse outside of JSX expressions. For example:

function NumberDescriber(props) {
  let Description;
  if (props.number % 2 == 0) {
    Description = <strong>even</strong>;
  } else {
    Description = <i>odd</i>;
  }
  return <div>{props.number} is an {Description} number</div>;
}

String text

You can also pass a string directly as a parameter. The following expression has the same effect:

//Direct use of strings
<MyComponent message="hello world" />

//Strings are passed in as a parameter in JavaScript expressions
<MyComponent message={'hello world'} />

If a string is passed directly, it will be parsed into an un-escaped HTML grammar. For example, the following two expressions will produce the same result:

//Input string
<MyComponent message="&lt;3" />

//Importing variables through JavaScript syntax
<MyComponent message={'<3'} />

Prop parameter defaults to "True"

If the prop parameter without data is passed, its value defaults to true. So the following two expressions are exactly the same:

<MyTextBox autocomplete />

<MyTextBox autocomplete={true} />

Usually this is not recommended because it confuses the abbreviation syntax of ES6 -- {foo} with {foo: foo} instead of {foo:true}. This feature is provided only because it is very similar to HTML grammar.

Property Extension Transfer (Spread feature)

If you already have a props of type object, and want to pass this props to JSX. The "..." syntax of ES6 can be used to extend the passing of the entire parameter. The following expression has the same effect:

function App1() {
  return <Greeting firstName="Ben" lastName="Hector" />;
}

function App2() {
  const props = {firstName: 'Ben', lastName: 'Hector'};
  return <Greeting {...props} />;
}

Attribute extension passing is a very useful feature, especially when parameters are variable. However, this feature also confuses the code and passes some insignificant parameters to the components. It is recommended that this feature be used cautiously.

Subtags in JSX

JSX expressions can use either open tags or closed tags (e.g., open tags: <div></div>). Closed label: <img/>. The content in the open tag is passed to the component through props.children.

Delivery string

A string can be passed between open tags, and the data obtained through props.children in the component is a string. This is useful for many built-in HTML tags. For example:

<MyComponent>Hello world!</MyComponent>

In the component "MyComponent", you can get the string "Hello world!" through props.children. You just need to write strings according to your requirements without considering HTML's transitional nature, so you write JSX to influence HTML code in this way:

<div>This is valid HTML &amp; JSX at the same time.</div>

JSX removes blank characters at the beginning and end, blank lines, and new lines adjacent to the label. Converts the line break and the whole line blank symbol in the middle of the text to a space character. Based on this feature, the following expressions have the same result:

//standard
<div>Hello World</div>

//Front-to-back line change
<div>
  Hello World
</div>

//Front-to-back line change, middle line change
<div>
  Hello
  World
</div>

//Front blank line, front change line.
<div>

  Hello World
</div>

Subelements of JSX

In the middle of JSX's open tags, you can set multiple sub-tags, and the contents of these tags can be obtained through props.children:

<MyContainer>
  <MyFirstComponent />
  <MySecondComponent />
</MyContainer>

You can also use multiple types of sub-elements at the same time, which is almost identical to HTML. We can think of the parsing process of JSX as an HTML, for example:

<div>
  Here is a list:
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
  </ul>
</div>

A React component cannot return more than one React element at a time, but a separate JSX expression can contain more than one sub-element, so we can use an outer tag to wrap the sub-element to render more than one React component.

JavaScript expressions as child elements

In the sub-elements of JSX, you can also use JavaScript expressions, and JSX uses {} to indicate that a JavaScript statement is to be executed. For example, the following two expressions have the same effect after they are executed:

<MyComponent>foo</MyComponent>

<MyComponent>{'foo'}</MyComponent>

In the development process, we often encounter the need to render a list of JSX expressions. We can directly embed iteration statements into sub-elements to process, for example:

function Item(props) {
  return <li>{props.message}</li>;
}

function TodoList() {
  const todos = ['finish doc', 'submit pr', 'nag dan to review'];
  return (
    <ul>
      {todos.map((message) => <Item key={message} message={message} />)}
    </ul>
  );
}

JavaScript expressions can be used in conjunction with any type of subelement, for example, as a template tool:

function Hello(props) {
  return <div>Hello {props.addressee}!</div>;
}

Function as a child element

Typically, embedding JavaScript expressions into JSX will be treated as a string, a React element, or a list of string and React elements. However, props.chilidren, like other props parameters, can pass any type of data, not just the type that React knows. For example, if you customize a self-built Repeat, the child element receives a list of methods and executes each method one by one in Repeat:

// prop.children receives a list of methods, each of which will be invoked one by one.
function Repeat(props) {
  let items = [];
  for (let i = 0; i < props.numTimes; i++) {
    items.push(props.children(i));
  }
  return <div>{items}</div>;
}

// numTimes conveys the number of cycles, while sub-elements are a series of methods. It will be executed in the Repeat component.
function ListOfTenThings() {
  return (
    <Repeat numTimes={10}>
      {(index) => <div key={index}>This is item {index} in the list</div>}
    </Repeat>
  );
}

Pros. children can pass any parameter to a custom component, as long as it is processed into an expression that React can understand before React renders, which can greatly extend the flexibility of JSX.

Booleans, Null, and Undefined are ignored

false, null, undefined, and true are all valid elements, which in expression mean "no rendering required". The following expressions will all yield the same result: _____________

<div />

<div></div>

<div>{false}</div>

<div>{null}</div>

<div>{undefined}</div>

<div>{true}</div>

Such a feature facilitates the writing of conditional expressions. For example, in the following example, the < Header /> element is rendered only when the showHeader is true:

 

<div>
  {showHeader && <Header />}
  <Content />
</div>

The falsy value needs to be specified in particular.( See mozilla's official note React renders a variable with a numeric value of 0. The following code still renders when the result of props.messages.length is 0:

<div>
  {props.messages.length &&
    <MessageList messages={props.messages} />
  }
</div>

You need to always keep & the results of previous expressions are boolean types, so in order to get the right results, we need to adjust the expressions to:

<div>
  {props.messages.length > 0 &&
    <MessageList messages={props.messages} />
  }
</div>

Finally, if you want to output false, true, null, or undefined to components, you need to convert them into strings( Explain):

<div>
  My JavaScript variable is {String(myVariable)}.
</div>

Posted by zeno on Fri, 12 Jul 2019 11:12:32 -0700