📜 ⬆️ ⬇️

JSX - details

React. Advanced Guides. Part one


With this publication, I open a series of translations of the Advanced Guides section of the official documentation of the React.js library.


JSX - details


Fundamentally, JSX is syntactic sugar for the React.createElement(component, props, ...children) function React.createElement(component, props, ...children) .



JSX code:


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

compiles to:


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

You can also use a self-closing form for tags that have no descendants. For example:


 <div className="sidebar" /> 

compiles to:


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

To test how different JSX constructs are compiled into JavaScript, you can use the Babel online compiler


React Item Type Specification


The initial part of the JSX tag determines the type of element React.


Types defined with an uppercase letter indicate that the tag refers to the React component. These tags in the compilation process refer to a named variable containing the React component. Therefore, note that this variable must be in scope. For example: If you use the expression JSX - <Foo /> , then the variable Foo should be in scope.


React must be in scope


Since JSX is compiled into calls to the React.createElement function, the React library must always be within the scope of your JSX code.


For example: both import lines are necessary in this code, since React and CustomButton not directly included in JavaScript:


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

If you are not using any JavaScript wrapper and add the React directly to the <script> , then React will always be in the global scope.


Using dot notation in JSX type


The React component can be referenced using dotted notation in JSX. This is useful if you have a module that exports several React components. For example, if MyComponents.DatePicker is a component, then you can use this notation directly in JSX:


 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" />; } 

Newly defined components that are not in the standard React library should be named with a capital letter.


If an element type is named with a lowercase letter, it means that the element is a built-in component such as a <div> or <span> and is passed as a string 'div' or 'span' to the React.createElement function. Capitalized types, such as <Foo /> are compiled as React.createElement(Foo) and refer to a component defined or imported in your JavaScript file.


We recommend naming the components with an uppercase letter. If you have a component named with a lowercase letter, before using it in JSX, assign it to a variable named with a capital letter.


For example, this code will not return what is expected of it:


 import React from 'react'; // !        : function hello(props) { // !  <div> , .. div   HTML : return <div>Hello {props.toWhat}</div>; } function HelloWorld() { // ! React  <hello />  HTML , ..     : return <hello toWhat="World" />; } 

To fix the error, we rename hello to Hello and use <Hello /> in JSX:


 import React from 'react'; // !       : function Hello(props) { // !  <div> , .. div   HTML : return <div>Hello {props.toWhat}</div>; } function HelloWorld() { // ! React ,  <Hello />  , ..     : return <Hello toWhat="World" />; } 

Type selection at runtime


You cannot use a generic expression in the React element type. If you need to use a general expression to determine the type of an element, first assign it to a variable named with an uppercase letter. This is often necessary to display different components depending on the value of the property in props:


 import React from 'react'; import { PhotoStory, VideoStory } from './stories'; const components = { photo: PhotoStory, video: VideoStory }; function Story(props) { // ! JSX     . return <components[props.storyType] story={props.story} />; } 

To correct the error, we assigned a type to a variable, named with an uppercase letter:


 import React from 'react'; import { PhotoStory, VideoStory } from './stories'; const components = { photo: PhotoStory, video: VideoStory }; function Story(props) { // ! JSX    ,    . const SpecificStory = components[props.storyType]; return <SpecificStory story={props.story} />; } 

Properties in JSX


There are several different ways to set properties in JSX.


Javascript expressions


You can place any JavaScript expression in a property by enclosing it in curly braces {} . For example:


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

For the MyComponent component MyComponent value of props.foo will be 10 , since the expression 1 + 2 + 3 + 4 will return such a result.


if or for loops are not expressions in JavaScript, so they cannot be used directly in JSX. Therefore, they must be used only in the surrounding code. 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 literals


String literals can be placed in properties. These two JSX expressions are equivalent:


 <MyComponent message="hello world" /> <MyComponent message={'hello world'} /> 

When a string literal is placed, its value will be HTML escaped. These two JSX expressions are equivalent:


 <MyComponent message="&lt;3" /> <MyComponent message={'<3'} /> 

Placing string literals directly in properties is usually not used and is given here only for completeness.


Default properties are true.


If you specify a property in the JSX component and do not specify its value, the default value of the property is set to true . These two JSX expressions are equivalent:


 <MyTextBox autocomplete /> <MyTextBox autocomplete={true} /> 

We do not recommend using this feature, since it is easily confused with the short notation of objects in ES6. For example: {foo} in ES6 is the short notation of the record {foo: foo} , and not {foo: true} . This feature is added only because of its presence in HTML.


Attribute Expansion


If you have an object that contains properties, and you want to pass it to JSX, you can use ... as the spread operator to transfer all the properties contained in the object. These two components are equivalent:


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

Attribute expansion can be useful when implementing generic containers. At the same time, unwrapping can make your code dirty, because when expanded into a component, all properties of the object are transferred as properties, including those that the component does not need and does not process. We recommend using this syntax carefully.


Child (children) in JSX


In a JSX expression that contains an opening and closing tag, the content enclosed between these tags is transferred to a special property: props.children during compilation. Let's look at the types of possible descendants:


String literals


You can insert a line between the opening and closing tags and the value of props.children will be equal to this line. The use of string literals is convenient for many embedded HTML elements.


It looks like this:


 <MyComponent>Hello world!</MyComponent> 

This valid JSX expression - the props.children component of the MyComponent set equal to the string "Hello world!" . Note that the value of the string literal will be HTML escaped when compiled, so in a generally simplified case, you can write your JSX code just as you write HTML:


 <div>     - &amp;.      HTML    JSX.</div> 

JSX removes spaces at the beginning and end of a line. It also deletes blank lines. Line breaks adjacent to tags will be deleted. Line breaks that are in the middle of a string literal and follow one after the other are converted to one line feed. Thus, the following examples will be displayed in the same way:


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

Jsx element


Other JSX elements can be descendants of a JSX element. This is useful for displaying nested components:


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

You can mix any type of descendants, be it strings or jsx elements. This is another option when JSX can also look like HTML. The following example is valid in JSX and HTML:


 <div>  : <ul> <li>1-  </li> <li>2-  </li> </ul> </div> 

The React component cannot return multiple React elements — in other words: the React component must always have only one top-level root element. At the same time, one JSX expression can have an unlimited number of descendants. Thus, if you do not have a top-level root element, simply wrap your set of elements in a div element, as in the previous example.


Javascript expressions


You can use any javascript expression as a child, simply by taking it in curly braces - {} . For example, the following expressions are equivalent:


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

This feature is often used to display a list of JSX expressions of arbitrary length. For example, this code displays a list of HTML:


 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 combined with other types of descendants. This is useful when displaying string patterns:


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

Javascript functions


As a rule, JavaScript expressions used in JSX return strings, React elements, or both. However, props.children works just like any other property to which any kind of data can be passed, and not just data of the types that React knows how to display. For example, you can define a certain component and receive a callback from it via props.children :


 function ListOfTenThings() { return ( <Repeat numTimes={10}> {(index) => <div key={index}>This is item {index} in the list</div>} </Repeat> ); } //  " -   " numTimes      function Repeat(props) { let items = []; for (let i = 0; i < props.numTimes; i++) { items.push(props.children(i)); } return <div>{items}</div>; } 

Anything can be passed to the component as a descendant. The main thing is that this component should convert and return by the time of rendering (rendering) what React knows how to display. Such use is not generally accepted, but it perfectly reflects what React is capable of.


Boolean values, Null and Undefined are ignored.


false , null , undefined and true can be used as descendants. But these values ​​are not displayed when rendering. The following JSX expressions will be displayed the same way:


 <div /> <div></div> <div>{false}</div> <div>{null}</div> <div>{true}</div> 

This feature, along with the feature for handling conditional expressions in JavaScript, can be used to conditionally display React elements. The following JSX expression will display <Header /> if the showHeader value is true :


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

However, there is a nuance when some "falsy" values , such as the number 0 , are displayed React. For example, the following code will not behave as expected, and in case props.messages will contain an empty array, 0 will be displayed as a result of rendering:


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

To correct the situation, make sure that the expression before && always boolean:


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

And vice versa, if you need to display false , true , null or undefined when rendering - convert them to a string :


 <div>   myVariable = {String(myVariable)}. </div> 

The following parts:



Original Source: React - Advanced Guides - JSX In Depth


')

Source: https://habr.com/ru/post/319270/


All Articles