📜  React 和 ReactDOM 是如何工作的?

📅  最后修改于: 2022-05-13 01:56:51.298000             🧑  作者: Mango

React 和 ReactDOM 是如何工作的?

当您使用 React 时,您很可能会使用 JSX 构建您的应用程序。 JSX 是一种基于标签的 JavaScript 语法,看起来很熟悉 HTML。 React 元素是在 JSX 之前和使用 React 之前需要掌握的原子和最基本的单元。

注意:为了在浏览器中使用 React,我们需要包含 2 个库:React 和 ReactDOM。 React 库负责创建视图,ReactDOM 库负责在浏览器中实际渲染 UI。

包括脚本:以下是 React 和 ReactDOM 的 CDN 链接:

React: https://cdnjs.com/libraries/react
ReactDOM: https://cdnjs.com/libraries/react-dom

在您的主 JavaScript 文件之前包含这两个库。在学习 React 的工作原理时,我们将使用 react 和 ReactDOM 构建一个小型应用程序。为简单起见,它在同一文件夹中仅包含 2 个文件index.htmlmain.js。您应该使用 React 开发版本在浏览器控制台中获取错误消息和警告。

HTML



  
  
  React | How React works


  
  
  



HTML
  

JavaScript Libraries and Frameworks

  
        
  • React.js
  •     
  • Angular
  •     
  • Vue.js
  •     
  • Node.js
  •     
  • underscore.js
  •   


Javascript
const root = document.querySelector( 'body' );
 
function createListElement() {
    const libsAndFrameworksNames = ['React.js', 'Angular', 'Vue.js',
    'Node.js', 'Underscore.js'];
     
    const ul = document.createElement( 'ul' );
    ul.classList.add( "list-lib-frameworks" );
 
    libsAndFrameworksNames.forEach( function appoendToUnorderedList( name ) {
        const listElement = document.createElement( 'li' );
        listElement.innerText = name;
        ul.appendChild( listElement );
    } );
 
    return ul;
}
 
function createWebPageWithJavaScript( root ) {
    // PARENT ELEMENT
    const parent = document.createElement( 'section' );
    parent.classList.add( 'js-section' );
     
    // HEADING ELEMENT
    const heading = document.createElement( 'h1' );
    heading.innerText = 'JavaScript Libraries and Frameworks';
 
    // UNORDERED LIST ELEMENT
    const unorderedListElement = createListElement();
 
    // APPEND HEADING AND UNORDERED LIST ELEMENT TO PARENT
    parent.appendChild(heading)
    parent.appendChild( unorderedListElement );
 
    // APPEND PARENT TO ROOT ELEMENT
    root.appendChild( parent );
}
 
createWebPageWithJavaScript( root );


Javascript
const mainReactElement = React.createElement(
    "section",
    { className: "js-section" },
    React.createElement( "h1", null, "JavaScript Libraries and Frameworks" ),
    React.createElement(
        "ul",
        { className: 'list-lib-frameworks' },
        React.createElement('li', null, 'React.js'),
        React.createElement('li', null, 'Angular'),
        React.createElement('li', null, 'Vue.js'),
        React.createElement('li', null, 'Node.js'),
        React.createElement('li', null, 'underscore.js'),
    )
);
 
ReactDOM.render(mainReactElement, document.querySelector( '#root' ));


Javascript
const listOfLibAndFrameworks = ['React.js', 'Angular', 'Vue.js',
'Node.js', 'underscore.js'];
 
const mainReactElement = React.createElement(
    "section",
    { className: "js-section" },
    React.createElement( "h1", null, "JavaScript Libraries and Frameworks" ),
    React.createElement(
        "ul",
        { className: 'list-lib-frameworks' },
        listOfLibAndFrameworks.map((element, index) => React.createElement('li',
        { key: index }, element))
    )
);
 
console.log( mainReactElement );
 
ReactDOM.render(mainReactElement, document.querySelector( '#root' ));



反应元素:

HTML 只是一组最终成为 DOM 元素的指令。假设您必须构建 JavaScript 库和框架的 HTML 层次结构。按照 HTML 命令为 JavaScript 库和框架创建 HTML 层次结构。

HTML

  

JavaScript Libraries and Frameworks

  
        
  • React.js
  •     
  • Angular
  •     
  • Vue.js
  •     
  • Node.js
  •     
  • underscore.js
  •   


在浏览器中,HTML 表示一个树状结构,节是根节点,它包含 2 个子节点,即h1ul。 ul也有一些子节点,即 5 li节点。在 DOM 中,它将表示为:

浏览器中的 DOM 表示

过去,网站由多个页面组成,当用户点击一个链接时,浏览器会请求一个新的 HTML 页面并再次构建 DOM。但是在 AJAX(异步 JavaScript 和 XML)的发明之后,给我们带来了单页应用程序(SPA)。在 SPA 中,浏览器首先加载初始 HTML 文档。当用户通过单击链接进行导航时,浏览器会发送请求,然后浏览器会更新 DOM 的一部分。感觉就像用户正在从一个页面跳到另一个页面。但是用户总是停留在同一页面上。 JavaScript 会破坏旧的 UI 并创建新的 UI。 JavaScript 在幕后做着繁重的工作。

JavaScript 如何更新 DOM?

JavaScript 使用 DOM API 来更新和操作 DOM 节点。 DOM API 只是 JavaScript 用来操作 DOM 的对象的集合。这里的操作是指 DOM 节点中的 CRUD(创建、读取、更新和删除)操作。如果你想构建 HTML 页面,我们也可以使用 vanilla JavaScript 构建。

Javascript

const root = document.querySelector( 'body' );
 
function createListElement() {
    const libsAndFrameworksNames = ['React.js', 'Angular', 'Vue.js',
    'Node.js', 'Underscore.js'];
     
    const ul = document.createElement( 'ul' );
    ul.classList.add( "list-lib-frameworks" );
 
    libsAndFrameworksNames.forEach( function appoendToUnorderedList( name ) {
        const listElement = document.createElement( 'li' );
        listElement.innerText = name;
        ul.appendChild( listElement );
    } );
 
    return ul;
}
 
function createWebPageWithJavaScript( root ) {
    // PARENT ELEMENT
    const parent = document.createElement( 'section' );
    parent.classList.add( 'js-section' );
     
    // HEADING ELEMENT
    const heading = document.createElement( 'h1' );
    heading.innerText = 'JavaScript Libraries and Frameworks';
 
    // UNORDERED LIST ELEMENT
    const unorderedListElement = createListElement();
 
    // APPEND HEADING AND UNORDERED LIST ELEMENT TO PARENT
    parent.appendChild(heading)
    parent.appendChild( unorderedListElement );
 
    // APPEND PARENT TO ROOT ELEMENT
    root.appendChild( parent );
}
 
createWebPageWithJavaScript( root );


输出:

输出与之前完全相同

但是随着我们的应用程序的增长,复杂性也在增长,并且很难维护。因此,为了克服复杂性,我们将使用 React 来为我们处理复杂性。

React是一个专门为我们与 DOM 交互而设计的库。从现在开始,我们不再直接更新 DOM,而是告诉 react 为我们更新 DOM。 React 将通过我们提供给 react 的命令为我们渲染和协调元素。

创建反应元素:

如前所述,React 元素是最小的实体。 React 元素只是一个描述内存中 DOM 元素的 JavaScript 对象。我们可以使用 React 的createElement方法创建一个 React 元素。

句法:

React.createElement(type, [props], [...children]);

参数:上述方法接受以下参数:

  • type:这是您要创建的元素的类型,即 div、ul、li、section 等。它也可以是另一个 react 元素。
  • props:它是一个 JavaScript 对象,包含构造 DOM 所需的属性或数据。
  • 子元素或内容:有子元素或内容来显示其他嵌套元素。它可能是节点的内容。

示例:如何在我们的应用程序中创建一个li元素:

const listElement = React.createElement( 'li', null, 'React.js' );
console.log( listElement );

createReact 元素的输出

说明:在上面的代码中,我们向createElement传递了 3 个参数,如下所示:

  1. li:它定义了我们要创建的元素的类型。在这种情况下,是列表元素。
  2. null:我们不想在列表元素中定义任何属性。我们可以将className属性传递给它,以在列表节点上定义类属性。但在我们的情况下,我们没有。因此,如果没有属性,我们必须从外部传递null
  3. React.js:第三个元素代表元素的子元素。插入在开始标签和结束标签之间的任何节点都应该在第三个参数中定义。在列表节点中,我们没有要插入的子节点,但我们确实有文本。所以我们将文本作为字符串传递。

在渲染过程中,React 将 React 元素转换为实际的 DOM 元素。

  • React.js
  • 但是如果你想在 list(

  • ) 元素中添加一个类,那么我们可以将第二个属性添加为:

    const listElement = React.createElement( 'li', {
        className: 'list'
    }, 'React.js' );
    
    console.log( listElement );

    如果我们使用class来代替className ,那么我们就会从 React 收到警告消息。此错误消息可能因版本而异。

    class属性成为 propsclassName属性 反应。以下可能是两个原因:

    • 我们从createElement得到的 React 元素/节点是 DOM 节点而不是 HTML 元素。正如我们所知, class是 HTML 属性的名称。一旦浏览器在 HTML 元素上看到class属性,它就会转换为属性,即className。为了测试它,写下以下代码:
    const ele = document.createElement('li');
    ele.classList.add('list');
    console.log( ele.className );  // list
    • 由于是 JavaScript 中的保留属性,所以我们不能将用作属性。 className被添加到 'li' React 元素的props属性中。我们在第二个参数中定义的属性是分配给道具 该 React 元素的属性。所以 React 将上面的列表元素转换为 DOM 元素,如下所示:
  • React.js
  • 反应DOM

    一旦你创建了 React 元素。然后你想在浏览器中看到它。但是浏览器不理解 React 元素。 ReactDOM 是在浏览器中呈现 React 元素的中间人。 ReactDOM 带有一些有用的方法,但我们感兴趣的方法是render 。它需要 2 个参数,分别描述为什么(您要渲染的元素)和位置(您要渲染的位置)。

    示例:在 DOM 中渲染上述列表元素( listElement )。

    const listElement = React.createElement( 'li', {
        className: 'list'
    }, 'React.js' );
    
    ReactDOM.render( listElement, document.querySelector( '#root' ) );

    这里 render 方法的第二个参数是我们要渲染listElement的位置或元素。我们可以使用 body 标签,如下所示:

    document.querySelector('body');

    它有效,但不推荐。 React 在开发模式下通过以下消息警告我们:

    如果我们想在正文中渲染 React 元素,则会出错。

    实现:以下是我们示例的最终main.js文件。

    文件名-main.js:

    Javascript

    const mainReactElement = React.createElement(
        "section",
        { className: "js-section" },
        React.createElement( "h1", null, "JavaScript Libraries and Frameworks" ),
        React.createElement(
            "ul",
            { className: 'list-lib-frameworks' },
            React.createElement('li', null, 'React.js'),
            React.createElement('li', null, 'Angular'),
            React.createElement('li', null, 'Vue.js'),
            React.createElement('li', null, 'Node.js'),
            React.createElement('li', null, 'underscore.js'),
        )
    );
     
    ReactDOM.render(mainReactElement, document.querySelector( '#root' ));
    


    如果您为createElement方法提供了 3 个以上的参数。然后 React 将其他参数视为子参数。所以 React 创建了一个由这些子元素组成的数组。这个新创建的数组将被分配给props.children数组。我们还可以使用数组的方法来让我们的代码更简洁,如下所示:

    Javascript

    const listOfLibAndFrameworks = ['React.js', 'Angular', 'Vue.js',
    'Node.js', 'underscore.js'];
     
    const mainReactElement = React.createElement(
        "section",
        { className: "js-section" },
        React.createElement( "h1", null, "JavaScript Libraries and Frameworks" ),
        React.createElement(
            "ul",
            { className: 'list-lib-frameworks' },
            listOfLibAndFrameworks.map((element, index) => React.createElement('li',
            { key: index }, element))
        )
    );
     
    console.log( mainReactElement );
     
    ReactDOM.render(mainReactElement, document.querySelector( '#root' ));
    


    React 只是 JavaScript。所以无论你可以用 JavaScript 做什么,你也可以用 React 做。在 React 中使用数组时,您会遇到 react 抱怨唯一键的时候。要删除此警告,我们可以使用如上所示的密钥。它用于通过 React 识别唯一列表,以便在使用时重新渲染它。它使我们的代码更有效率。强烈建议在使用列表时添加关键属性。

    如果你不添加密钥,那么 React 会抛出以下警告:

    所以不要忘记在 props 中添加key属性。如果我们记录mainReactElement ,那么我们可以看到使用传递给 React 的createElement方法的附加参数创建的数组。