react学习

1. React概述

1.1 什么是react?

React 是一个用于构建用户界面的 JavaScript 库
用户界面:HTML页面(前端)
React 主要用来写HTML页面,或构建Web应用如果从 MVC 的角度来看,React 仅仅是视图层(V),也就是只负责视图的染,而并非提供了完整的M和C的功能
React 起源于Facebook 的内部项目,后又用来架设Instagram 的网站,并于2013年5月开源

 1.1react特点

1.声明式

        你只需要描述 UI(HTML)看起来是什么样,就跟写HTML一样React负责渲染 UI,并在数据变化时更新 UI

const jsx = <div className="app">
    <h1>Hello React!动态变化数据:(countj</h1>
</div>

2.基于组件

  • 组件是 React 最重要的内容
  • 组件表示页面中的部分内容
  • 组合、复用多个组件,可以实现完整的页面功能

 3.学习一次 随处可用

  • 使用 React 可以开发Web应用
  • 使用 React 可以开发移动端原生应用(react-native)
  • 使用 React 可以开发VR(虚拟现实)应用(react 360)

2. React基本使用

2.1 React安装

安装命令:npm i react react-dom

  • react 包是核心,提供创建元素、组件等功能
  • react-dom 包提供 DOM 相关功能等

 2.2 React使用

1. 引入 react 和 react-dom 两个 js 文件

2. 创建 React 元素

3. 渲染 React 元素到页面中

<div id="root"></div>
<script>
    const title = React.createElement('h1',null,'hello React')
    ReactDOM.render(title, document.getElementById('root'))
</script>

2.2 方法说明

React.createElement() 说明(知道)

// 返回值:React元素

// 第一个参数:要创建的React元素名称

// 第二个参数:该React元素的属性

// 第三个及其以后的参数:该React元素的子节点 const el = React.createElement('h1', { title: '标题' }, 'Hello React')

ReactDOM.render() 说明 

// 第一个参数:要渲染的React元素

// 第二个参数:DOM对象,用于指定渲染到页面中的位置

ReactDOM.render(el, document.getElementById('root'))

2.3 CDN方式

    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

<script type="text/babel">
    书写react内容
</script>

3. React 脚手架的使用

3.1 React 脚手架意义

  1. 脚手架是开发 现代Web 应用的必备。
  2. 充分利用 Webpack、Babel、ESLint 等工具辅助项目开发。
  3. 零配置,无需手动配置繁琐的工具即可使用。
  4. 关注业务,而不是工具配置。

3.2 使用 React 脚手架初始化项目

1. 初始化项目,命令:npx create-react-app my-app

2. 启动项目,在项目根目录执行命令:npm start

npx 命令介绍 

  • npm v5.2.0 引入的一条命令
  • 目的:提升包内提供的命令行工具的使用体验 
  • 原来:先安装脚手架包,再使用这个包中提供的命令
  • 现在:无需安装脚手架包,就可以直接使用这个包提供的命令

补充说明

1. 推荐使用:npx create-react-app my-app

2. npm init react-app my-app

3. yarn create react-app my-app

  • yarn 是 Facebook 发布的包管理器,可以看做是 npm 的替代品,功能与 npm 相同
  • yarn 具有快速、可靠和安全的特点
  • 初始化新项目:yarn init
  • 安装包: yarn add 包名称
  • 安装项目依赖项: yarn
  • 其他命令,请参考yarn文档

3.3 在脚手架中使用 React

1. 导入 react 和 react-dom 两个包。

import React from 'react'

import ReactDOM from 'react-dom'

2. 调用 React.createElement() 方法创建 react 元素。

3. 调用 ReactDOM.render() 方法渲染 react 元素到页面中。 

基础总结

React 基础

  1. React是构建用户界面的JavaScript库
  2. 使用 react 时,推荐使用脚手架方式。
  3. 初始化项目命令:npx create-react-app my-app 。
  4. 启动项目命令:yarn start(或 npm start)。
  5. React.createElement() 方法用于创建 react 元素(知道)。
  6. ReactDOM.render() 方法负责渲染 react 元素到页面中。

react(B站李立超-18)

1. hello world

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
    <!--引入react的核心库-->
    <script src="script/react.development.js"></script>
    <!--引入react的DOM库-->
    <script src="script/react-dom.development.js"></script>
</head>
<body>

<div id="root"></div>

<script>
    /*
    *   React就是用来代替DOM的
    * */

    // 通过DOM向页面中添加一个div
    // 创建一个div
    // const div = document.createElement('div'); // 创建一个dom元素
    // // 向div中设置内容
    // div.innerText = '我是一个div';
    // // 获取root
    // const root = document.getElementById('root');
    // // 将div添加到页面中
    // root.appendChild(div);


    // 通过React向页面中添加一个div
    /*
    *   React.createElement()
    *       - 用来创建一个React元素
    *       - 参数:
    *           1. 元素名(组件名)
    *           2. 元素中的属性
    *           3. 元素的子元素(内容)
    * */
    const div = React.createElement('div', {}, '我是React创建的div'); // 创建一个React元素

    // 获取根元素对应的React元素
    //  ReactDOM.createRoot() 用来创建React根元素,需要一个DOM元素作为参数
    const root = ReactDOM.createRoot(document.getElementById('root'));

    // 将div渲染到根元素中
    root.render(div);



</script>
</body>
</html>

2. 3个API

  1. React.createElement
  2. ReactDOM.createRoot
  3. ReactDOM.createRoot 的render方法

    /*
    * React.createElement()
    *   - 用来创建一个React元素
    *   - 参数:
    *        1.元素的名称(html标签必须小写)
    *        2.标签中的属性
    *           - class属性需要使用className来设置
    *           - 在设置事件时,属性名需要修改为驼峰命名法
    *       3.元素的内容(子元素)
    *   - 注意点:
    *       React元素最终会通过虚拟DOM转换为真实的DOM元素
    *       React元素一旦创建就无法修改,只能通过新创建的元素进行替换
    * */

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>三个API</title>
    <script src="script/react.development.js"></script>
    <script src="script/react-dom.development.js"></script>
</head>
<body>
<button id="btn">我是按钮</button>
<div id="root"></div>

<script>
    // 创建一个React元素
    const button = React.createElement('button', {
        type: 'button',
        className: 'hello',
        onClick: () => {
            alert('你点我干嘛')
        }
    }, '点我一下');

    // 创建第一个div
    const div = React.createElement('div', {}, '我是一个div', button);

    // 获取根元素
    const root = ReactDOM.createRoot(document.getElementById('root'));

    // 将元素在根元素中显示
    root.render(div);

    // 获取按钮对象
    const btn = document.getElementById('btn');
    btn.addEventListener('click', ()=>{
        // 点击按钮后,修改div中button的文字为click me
        const button = React.createElement('button', {
            type: 'button',
            className: 'hello',
            onClick: () => {
                alert('你点我干嘛')
            }
        }, 'click me');

        // 创建一个div
        const div = React.createElement('div', {}, '我是一个div', button);

        // 修改React元素后,必须重新对根元素进行渲染
        // 当调用render渲染页面时,React会自动比较两次渲染的元素,只在真实DOM中更新发生变化的部分
        //      没发生变化的保持不变
        root.render(div);
    });
</script>

</body>
</html>

   /*
    *   root.render()
    *       - 用来将React元素渲染到根元素中
    *       - 根元素中所有的内容都会被删除,被React元素所替换
    *       - 当重复调用render()时,React会将两次的渲染结果进行比较,
    *           它会确保只修改那些发生变化的元素,对DOM做最少的修改
    * */

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>三个API</title>
    <script src="script/react.development.js"></script>
    <script src="script/react-dom.development.js"></script>
</head>
<body>
<div id="root">
</div>

<script>

    // 创建一个React元素
    const button = React.createElement('button', {
        type: 'button',
        className: 'hello',
        onClick: () => {
            alert('你点我干嘛')
        }
    }, '点我一下');

    // 创建第一个div
    const div = React.createElement('div', {}, '我是一个div2', button);


    // ReactDOM.render(div, document.getElementById('root')); // 老版本的React中使用方法

    // 获取根元素 根元素就是React元素要插入的位置
    const root = ReactDOM.createRoot(document.getElementById('root'));

    // 将元素在根元素中显示
 
    root.render(div);

</script>

</body>
</html>

3. JSX

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <title>JSX</title>
    <script src="script/react.development.js"></script>
    <script src="script/react-dom.development.js"></script>
    <!-- 引入babel -->
    <script src="script/babel.min.js"></script>
</head>

<body>
    <div id="root"></div>

    <!--设置js代码被babel处理-->
    <script type="text/babel">

         创建一个React元素 <button>我是按钮</button>
         命令式编程
         const button = React.createElement('button', {}, '我是按钮');

         声明式编程,结果导向的编程
         在React中可以通过JSX(JS扩展)来创建React元素,JSX需要被翻译为JS代码,才能被React执行
         要在React中使用JSX,必须引入babel来完成“翻译”工作
         const button = <button>我是按钮</button>; // React.createElement('button', {}, '我是按钮');

        /*
        *   JSX就是React.createElement()的语法糖
        *       JSX在执行之前都会被babel转换为js代码
        * */
        const div = <div>
            我是一个div
            <button>我是按钮</button>
        </div>;

        const root = ReactDOM.createRoot(document.getElementById('root'));
        root.render(div);

    </script>
</body>

</html>

    /*

    *   JSX的注意事项

    *       1. JSX不是字符串,不要加引号

    *       2. JSX中html标签应该小写,React组件应该大写开头

    *       3. JSX中有且只有一个根标签

    *       4. JSX的标签必须正确结束(自结束标签必须写/)

    *       5. 在JSX中可以使用{}嵌入表达式

    *              - 有值的语句的就是表达式

    *       6. 如果表达式是空值、布尔值、undefined,将不会显示

    *       7. 在JSX中,属性可以直接在标签中设置

    *           注意:

    *               class需要使用className代替

    *               style中必须使用对象设置

    *                   style={{background:'red'}}

    * */

<!DOCTYPE html>
<html lang="zh">

<head>
    <meta charset="UTF-8">
    <title>JSX的注意</title>
    <script src="script/react.development.js"></script>
    <script src="script/react-dom.development.js"></script>
    <!-- 引入babel -->
    <script src="script/babel.min.js"></script>
</head>

<body>
    <div id="root"></div>

    <script type="text/babel">
        function fn() {
            return 'hello';
        }

        const name = '孙悟空';

        const div = <div
            id="box"

            onClick={() => {
                alert('哈哈')
            }} className="box1"

            style={{ backgroundColor: "yellowgreen", border: '10px red solid' }}
        >
            我是一个div
            <ul>
                <li>列表项</li>
            </ul>

            <input type="text" />

            <div>
                {name} <br />
                {1 + 1} <br />
                {fn()} <br />
                {NaN} <br />
            </div>
        </div>;

        // alert(div);

        const root = ReactDOM.createRoot(document.getElementById('root'));
        root.render(div);
    </script>
</body>

</html>

 4. 列表渲染

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>渲染列表</title>
    <script src="script/react.development.js"></script>
    <script src="script/react-dom.development.js"></script>
    <!-- 引入babel -->
    <script src="script/babel.min.js"></script>
</head>
<body>
<div id="root"></div>

<script type="text/babel">

    const name = '孙悟空';
    const lang = 'cn';

    /*
    *   {} 只能用来放js表达式,而不能放语句(if for)
    *       在语句中是可以去操作JSX
    * */
    // const div = <div>Hello {name}</div>;

    let div;

    if(lang === 'en'){
        div = <div>hello {name}</div>;
    }else if(lang === 'cn'){
        div = <div>你好 {name}</div>;
    }

    const data = ['孙悟空', '猪八戒', '沙和尚'];

    /*
        <ul>
             <li>孙悟空</li>
             <li>猪八戒</li>
            ...
        </ul>

        [<li>孙悟空</li>, <li>猪八戒</li>, <li>沙和尚</li>]
    * */

    // const arr = [];

    // 遍历data
    // for(let i=0; i<data.length; i++){
    //     arr.push(<li>{data[i]}</li>);
    // }

    // const arr = data.map(item => <li>{item}</li>);


    // 将arr渲染为一个列表在网页中显示
    // jsx中会自动将数组中的元素在页面中显示
    // const list = <ul>{arr}</ul>;

    const list = <ul>{data.map(item => <li>{item}</li>)}</ul>;

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(list);

</script>
</body>
</html>

5. 虚拟DOM

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>虚拟DOM</title>
    <script src="script/react.development.js"></script>
    <script src="script/react-dom.development.js"></script>
    <script src="script/babel.min.js"></script>
</head>
<body>
<button id="btn">点我一下</button>
<hr>
<div id="root"></div>

<script type="text/babel">

    //创建一个数据
    const data = ['孙悟空', '猪八戒', '沙和尚'];

    // 创建列表
    const list = <ul>
        {/*data.map(item => <li key={item}>{item}</li>)*/}
        {data.map((item, index) => <li key={index}>{item}</li>)}
    </ul>;

    // 获取根元素
    const root = ReactDOM.createRoot(document.getElementById('root'));
    // 渲染元素
    root.render(list);

    /*
    *   在React我们操作的元素被称为React元素,并不是真正的原生DOM元素,
    *       React通过虚拟DOM 将React元素 和 原生DOM,进行映射,虽然操作的React元素,但是这些操作最终都会在真实DOM中体现出来
    *       虚拟DOM的好处:
    *           1.降低API复杂度
    *           2.解决兼容问题
    *           3.提升性能(减少DOM的不必要操作)
    *
    *   每当我们调用root.render()时,页面就会发生重新渲染
    *       React会通过diffing算法,将新的元素和旧的元素进行比较
    *       通过比较找到发生变化的元素,并且只对变化的元素进行修改,没有发生的变化不予处理
    * */
    document.getElementById('btn').onclick = function (){
        // 重新渲染页面
        //创建一个数据
        const data = ['唐僧', '孙悟空', '猪八戒', '沙和尚'];
        // 创建列表
        const list = <ul>
            {/*data.map(item => <li key={item}>{item}</li>)*/}
            {data.map((item, index) => <li key={index}>{item}</li>)}
        </ul>;
        // 渲染元素
        root.render(list);

        /*
        *   旧数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *  新数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *   比较两次数据时,React会先比较父元素,父元素如果不同,直接所有元素全部替换
        *       父元素一致,在去逐个比较子元素,直到找到所有发生变化的元素为止
        *   上例中,新旧两组数据完全一致,所以没有任何DOM对象被修改
        *
        *
        * 旧数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *  新数据
        *       ul
        *           li>tom
        *           li>猪八戒
        *           li>沙和尚
        *
        *  上例中,只有第一个li发生变化,所以只有第一个li被修改,其他元素不变
        *
        *  当我们在JSX中显示数组中,数组中每一个元素都需要设置一个唯一key,否则控制台会显示红色警告
        *       重新渲染页面时,React会按照顺序依次比较对应的元素,当渲染一个列表时如果不指定key,同样也会按照顺序进行比较,
        *       如果列表的顺序永远不会发生变化,这么做当然没有问题,但是如果列表的顺序会发生变化,这可能会导致性能问题出现
        *
        *
        *   旧数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *   新数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *           li>唐僧
        *
        *   上例中,在列表的最后添加了一个新元素,并没有改变其他的元素的顺序,所以这种操作不会带来性能问题
        *
        *
        *
        *   旧数据
        *       ul
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *   新数据
        *       ul
        *           li>唐僧
        *           li>孙悟空
        *           li>猪八戒
        *           li>沙和尚
        *
        *   上例中,在列表的最前边插入了一个新元素,其他元素内容并没有发生变化,
        *       但是由于新元素插入到了开始位置,其余元素的位置全都发生变化,而React默认是根据位置比较元素
        *       所以 此时,所有元素都会被修改
        *
        *   为了解决这个问题,React为列表设计了一个key属性,
        *       key的作用相当于ID,只是无法在页面中查看,当设置key以后,再比较元素时,
        *       就会比较相同key的元素,而不是按照顺序进行比较
        *   在渲染一个列表时,通常会给列表项设置一个唯一的key来避免上述问题
        *       (这个key在当前列表中唯一即可)
        *       注意:
        *           1.开发中一般会采用数据的id作为key
        *           2.尽量不要使用元素的index作为key
        *               索引会跟着元素顺序的改变而改变,所以使用索引做key跟没有key是一样的
        *                   唯一的不同就是,控制台的警告没了
        *               当元素的顺序不会发生变化时,用索引做key也没有什么问题
        *   旧数据
        *       ul
        *           li(key=孙悟空)>孙悟空
        *           li(key=猪八戒)>猪八戒
        *           li(key=沙和尚)>沙和尚
        *   新数据
        *       ul
        *           li(key=唐僧)>唐僧
        *           li(key=孙悟空)>孙悟空
        *           li(key=猪八戒)>猪八戒
        *           li(key=沙和尚)>沙和尚
        * */
    };



</script>
</body>
</html>

6. 手动创建React

项目结构


常规的React项目需要使用npm(或yarn) 作为包管理器来对项目进行管理。并且React官方为了方便我们的开发,为我们提供react-scripts包。包中提供了项目开发中的大部分依赖,大大的简化了项目的开发


开发步骤:

  • 创建目录结构

根元素 

        - public

                - index.html

        - src

                - App.js

                - index.js

...

  • 进入项目所在目录,并执行命令: npm init -yyarn init -y
  • 安装项目依赖: npm install readt react-dom react-scripts - S 或 yarn add reactreact-dom react-scripts
  • 运行npx react-scripts start 启动项目 (初次启动需要输入y确认)
  • 或者将react-scripts start 设置到package.json 的scripts选项中,然后通过npm start启动 (初次启动需要输入y确认)"scripts":[“start":“react-scripts start”了 

7. 练习 学习记录器


js部分:

import React from "react";
import ReactDOM from "react-dom/client";

// 引入css 
import "./index.css"

// 创建 JSX

const App = <div className="logs">
    {/* 日志项容器 */}
    <div className="item">
        {/* 日期容器 */}
        <div className="date">
            <div className="month">四月</div>
            <div className="day">19</div>
        </div>
        {/* 日志内容容器  */}
        <div className="content">
            <h2 className="desc">学习React</h2>
            <div className="time">40分钟</div>
        </div>
    </div>

</div>

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(App)

css部分:

/*设置基本样式*/
*{
    box-sizing: border-box;
}

/*设置body的样式*/
body{
    background-color: #DFDFDF;
    margin: 0;
}

/*设置外层容器logs的样式*/
.logs{
    width: 800px;
    margin: 50px auto;
    padding: 20px;
    background-color: #EAE2B7;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0,0,0,.2);
}

/*设置item的样式*/
.item{
    /*开启弹性盒*/
    display: flex;
    margin: 16px 0;
    padding: 6px;
    background-color: #FCBF49;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0,0,0,.2);
}

/*设置日期的样式*/
.date{
    width: 90px;
    background-color: #fff;
    border-radius: 10px;
    font-weight: bold;
    text-align: center;
    overflow: hidden;
}

/*设置月份效果*/
.month{
    height: 30px;
    line-height: 30px;
    font-size: 20px;
    color: #fff;
    background-color: #D62828;
}

/*设置日期的效果*/
.day{
    height: 60px;
    line-height: 60px;
    font-size: 50px;
}

/*设置日志内容的样式*/
.content{
    flex: auto;
    text-align: center;
    font-weight: bold;
}

/*设置描述内容*/
.desc{
    font-size: 16px;
    color: #194B49;
}

/*设置学习时间*/
.time{
    color: #D62828;
}

8. 组件

在React中网页被拆分为了一个一个组件,组件是独立可复用的代码片段。具体来说,组件可能是页面中的一个按钮,一个对话框,一个弹出层等。React中定义组件的方式有两种: 基于函数的组件和基于类的组件。本书我们先看看基于函数的组件。


基于函数的组件其实就是一个会返回JSX (React元素) 的普通的JS函数,你可以这样定义:

 函数组件

const App = () => {
  return <div>我是App组件!</div>
};

// 导出App
export default App;





*   组件

*       - React中组件有两种创建方式

*       - 函数式组件

*           - 函数组件就是一个返回JSX的普通

*           - 组件的首字母必须是大写

*       - 类组件

import React from 'react'
import ReactDOM from "react-dom/client";
import App from "./App";


const root = ReactDOM.createRoot(document.getElementById('root'));

// React组件可以直接通过JSX渲染
root.render(<App />);

类组件

import React from "react";


*   类组件必须要继承React.Component
*       相较于函数组件,类组件的编写要麻烦一下,
*           但是他俩的功能是一样的

class App extends React.Component{

    // 类组件中,必须添加一个render()方法,且方法的返回值要是一个jsx
    render() {
        return <div>我是一个类组件</div>;
    }
}

// 导出App
export default App;



import ReactDOM from "react-dom/client";
import App from "./App";


const root = ReactDOM.createRoot(document.getElementById('root'));

// React组件可以直接通过JSX渲染
root.render(<App/>);

9. 组件练习

组件化的方式 

10. 事件 

React中的事件处理类似于在HTML标签中通过属性来设置事件,像是这样:

<button οnclick="alert("你点我干嗨");">点我一下</button>

这是传统DOM中绑定事件的方式之一,onclick全都小写是事件的名字,它的值是一组JS代码,当事件触发时,JS代码便会执行。记住这一点,传统DOM中事件属性的JS代码在事件触发时执行!

React中的事件绑定是这样的: 

App.js:

const App = () => {

    const clickHandler = (event) => {
        event.preventDefault(); // 取消默认行为
        event.stopPropagation(); // 取消事件的冒泡

        alert('我是App中的clickHandler!');
        
        *     在React中,无法通过return false取消默认行为
        *     return false;
        *
        *     事件对象
        *         - React事件中同样会传递事件对象,可以在响应函数中定义参数来接收事件对象
        *         - React中的事件对象同样不是原生的事件对象,是经过React包装后的事件对象
        *         - 由于对象进行过包装,所以使用过程中我们无需再去考虑兼容性问题
        
    };


    return <div
        onClick={() => {
            alert('div');
        }}
        style={{width: 200, height: 200, margin: '100px auto', backgroundColor:'#bfa'}}>

        {/*
      在React中事件需要通过元素的属性来设置,
        和原生JS不同,在React中事件的属性需要使用驼峰命名法:
           onclick -> onClick
           onchange -> onChange
        属性值不能直接执行代码,而是需要一个回调函数:
          onclick="alert(123)"
          onClick={()=>{alert(123)}}
    */}
        <button onClick