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 脚手架意义
- 脚手架是开发 现代Web 应用的必备。
- 充分利用 Webpack、Babel、ESLint 等工具辅助项目开发。
- 零配置,无需手动配置繁琐的工具即可使用。
- 关注业务,而不是工具配置。
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 基础
- React是构建用户界面的JavaScript库
- 使用 react 时,推荐使用脚手架方式。
- 初始化项目命令:npx create-react-app my-app 。
- 启动项目命令:yarn start(或 npm start)。
- React.createElement() 方法用于创建 react 元素(知道)。
- 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
- React.createElement
- ReactDOM.createRoot
-
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 -y 或 yarn 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