React 之 基础与核心语法

一、React基础-初体验
1. react
React:用于构建用户界面的 JavaScript 库
2. react特点

声明式
声明式编程:
-
声明式编程是目前整个大前端开发的模式:Vue、React、Flutter、SwiftUI
-
它允许我们只需要维护自己的状态,当状态改变时,React可以根据最新的状态去渲染我们的UI界面

组件化
组件化开发:将复杂的界面拆分成一个个小的组件

多平台适配
-
开发Web页面
-
ReactNative,用于开发移动端跨平台
-
ReactVR,用于开发虚拟现实Web应用程序

3. React的开发依赖概念
开发React必须依赖三个库:
-
react:包含react所必须的核心代码
-
react-dom:react渲染在不同平台所需要的核心代码
-
babel:将jsx转换成React代码的工具
react
react包中包含了react web和react-native所共同拥有的核心代码
react-dom
在React的0.14版本之前是没有react-dom这个概念的,所有功能都包含在react里
原因就是react-native
-
react-dom针对web和native所完成的事情不同
-
web端:react-dom会将jsx最终渲染成真实的DOM,显示在浏览器中
-
native端:react-dom会将jsx最终渲染成原生的控件(比如Android中的Button,iOS中的UIButton)
babel
babel : 是目前前端使用非常广泛的编译器、转移器。
-
Babel,又名 Babel.js
-
当下很多浏览器并不支持ES6的语法,通过Babel工具,将ES6转成大多数浏览器都支持的ES5语法
-
在react中,直接编写jsx(JavaScript XML)的语法,并且让babe转换成React.createElement
-
可不使用babel,但是要用 React.createElement 来编写源代码,它编写的代码非常的繁琐和可读性差
4. React的开发依赖引入
方式一:通过npm管理
ps : 后续脚手架中使用
方式二:CDN引入
crossorigin属性 :目的是为了拿到跨域脚本的错误信息
ps : 也可以下载依赖包到本地,然后本地引入
-
react
-
https://unpkg.com/react@18/umd/react.development.js
-
react-dom
-
https://unpkg.com/react-dom@18/umd/react-dom.development.js
-
babel
-
https://unpkg.com/babel-standalone@6/babel.min.js
5. 渲染概念理解
script标签
script : 添加 type="text/babel",作用是可以让babel解析jsx的语法
ReactDOM. createRoot
ReactDOM.createRoot函数:用于创建一个React根,之后渲染的内容会包含在这个根中
root.render
root.render函数 : 要渲染的根组件
6. 案例一 - hello world
01 - 初体验
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><!-- 导入三个依赖 --><script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script><script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script></head><body><div id="root"></div><div id="app"></div><script type="text/babel">// react 16的写法// ReactDOM.render(<h2>123123</h2>, document.querySelector('#root'));// react 16const root = ReactDOM.createRoot(document.querySelector('#root'));// 创建两个跟const app = ReactDOM.createRoot(document.querySelector('#app'));// 渲染root.render(<h2>hello world</h2>);app.render(<h2>hello react</h2>);</script></body>
</html>
02 - 初步优化 : 变量和事件
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><!-- 导入三个依赖 --><script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script><script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script><script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script></head><body><div id="root"></div><script type="text/babel">const root = ReactDOM.createRoot(document.querySelector('#root'));// 2. 定义变量let message = 'world';// 4. 监听按钮点击const btnClick = () => {// 5. 修改数据message = message === 'react' ? 'world' : 'react';// 6. 重新渲染一次,不会自动重新执行render,需要手动rootRender();};// 1. 默认调用一次rootRender();// 封装渲染流程function rootRender() {root.render(<div><h2>3. 变量 : hellow {message}</h2><button onClick={btnClick}>修改文本</button></div>);}</script></body>
</html>
03 - 再次优化:组件化开发重构
暂时使用类的方法封装组件
-
定义一个类(类名大写,组件的名称是必须大写的,小写会被认为是HTML元素)
-
继承自React.Component
-
实现当前组件的render函数
-
render当中返回的jsx内容,就是之后React渲染的内容
<script type="text/babel">// 封装类组件class App extends React.Component {// 渲染内容 render 方法render() {return (<div><h2>hello world</h2></div>);}}// 将组件渲染到界面上const root = ReactDOM.createRoot(document.querySelector('#root'));root.render(<App />);
</script>
组件化 - 数据依赖
在组件中的数据,可以分成两类:
-
参与界面更新的数据:当数据变量时,需要更新组件渲染的内容
-
不参与界面更新的数据:当数据变量时,不需要更新将组建渲染的内容
参与界面更新的数据也可以称之为是参与数据流,这个数据是定义在当前对象的state中
-
可以通过在构造函数中 this.state = {定义的数据}
-
当数据发生变化时,可以调用 this.setState 来更新数据,并且通知React进行update操作
-
在进行update操作时,就会重新调用render函数,并且使用最新的数据,来渲染界面
<script type="text/babel">// 封装类组件class App extends React.Component {// 1. 组件数据constructor() {super();// 动态的数据,需要放在这里!this.state = {message: 'hello world'};}// 2. 渲染内容 render 方法render() {return (<div><h2>{this.state.message}</h2></div>);}}// 将组件渲染到界面上const root = ReactDOM.createRoot(document.querySelector('#root'));root.render(<App />);
</script>
组件化 – 事件绑定
-
React 事件的命名采用小驼峰式(camelCase),而不是纯小写 => onClick
-
需要通过{}传入一个事件处理函数,这个函数会在事件发生时被执行
<script type="text/babel">// 封装类组件class App extends React.Component {// 1. 组件数据constructor() {super();// 动态的数据,需要放在这里!this.state = {message: 'hello world'};}// 2. 组件方法( 实例方法 )btnClick() {/* this为undefined => this.btnClick* 需要绑定this过来 => this.btnClick.bind(this)*/// 修改数据 this.setState为继承类里面的方法/* 内部完成了两件事情* 1. 将state中的message的值修改掉* 2. 自动重新执行render函数*/this.setState({message: 'hello react'});}// 3. 渲染内容 render 方法render() {console.log(this); // 这里有当前的实例return (<div><h2>{this.state.message}</h2><button onClick={this.btnClick.bind(this)}>修改文本</button></div>);}}// 将组件渲染到界面上const root = ReactDOM.createRoot(document.querySelector('#root'));root.render(<App />);
</script>
7. 案列二 - 列表展示
<body><div id="root"></div><script type="text/babel">class App extends React.Component {constructor() {super();this.state = {list: ['星际穿越', '火影大战猪猪侠', '海绵宝宝泡泡堂', '爱情公寓']};}render() {return (// 循环<ul>{this.state.list.map((item) => {return <li key={item}>{item}</li>;})}</ul>);}}const root = ReactDOM.createRoot(document.querySelector('#root'));root.render(<App />);</script>
</body>
8. 案例三 - 计数器案例
<body><div id="root"></div><script type="text/babel">class App extends React.Component {constructor() {super();this.state = {count: 0};}increment = () => {this.setState({count: this.state.count + 1});};decrement = () => {this.setState({count: this.state.count - 1});};render() {const { count } = this.state;return (<div><h1>当前计数 : {count}</h1><button onClick={this.increment}>+1</button><button onClick={this.decrement}>-1</button></div>);}}const root = ReactDOM.createRoot(document.querySelector('#root'));root.render(<App />);</script>
</body>
9. 生成代码片段

"react-html-demo": {"prefix": "react-html","body": ["<!DOCTYPE html>","<html lang=\\"en\\">"," <head>"," <meta charset=\\"UTF-8\\" />"," <meta http-equiv=\\"X-UA-Compatible\\" content=\\"IE=edge\\" />"," <meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />"," <title>Document</title>"," <script src=\\"./lib/react.js\\"></script>"," <script src=\\"./lib/react-dom.js\\"></script>"," <script src=\\"./lib/babel.js\\"></script>"," </head>"," <body>"," <div id=\\"root\\"></div>"," <script type=\\"text/babel\\">"," /"," * 创建App组件"," */"," class App extends React.Component {"," constructor() {"," super();"," this.state = {"," counter: 10"," };"," }"," render() {"," const { counter } = this.state;",""," return ("," <div>"," <h1>当前计数 : {counter}</h1>"," </div>"," );"," }"," }",""," /"," * 创建根组件并渲染"," */"," const root = ReactDOM.createRoot(document.querySelector('#root'));"," root.render(<App />);"," </script>"," </body>","</html>",""],"description": "react-html-demo"
}
二、React基础 - JSX语法
1. 概念
JSX : React - JSX
-
JSX是一种JavaScript的语法扩展(eXtension),也在很多地方称之为JavaScript XML
-
因为看起就是一段XML语法
-
用于描述我们的UI界面,并且其完成可以和JavaScript融合在一起使用 => html in js
-
不同于Vue中的模块语法,不需要学习模块语法中的一些指令
-
比如v-for、v-if、v-else、v-bind

2. 为什么React选择了JSX
React认为渲染逻辑本质上与其他UI逻辑存在内在耦合 => html、css、js分不开,干脆写到一起
-
比如UI需要绑定事件(button、a原生等等)
-
比如UI中需要展示数据状态
-
比如在某些状态发生改变时,又需要改变UI
-
他们之间是密不可分,所以React没有将标记分离到不同的文件中,而是将它们组合到了一起
-
这个地方就是组件(Component)
3. JSX书写规范
-
1. JSX的顶层只能有一个根元素
-
所以我们很多时候会在外层包裹一个div元素(或者使用后面我们学习的Fragment)
-
2. 为了方便阅读,通常在jsx的外层包裹一个小括号()
-
这样可以方便阅读,并且jsx可以进行换行书写
-
3. JSX中的标签可以是单标签,也可以是双标签
-
如果是单标签,必须以/>结尾
-
4. JSX中注释的写法 => [ .jsx文件中 -- ctrl + / ] 即可
render() {const { counter } = this.state;return (<div>{// 注释的写法1}{/* 注释的写法2 */}<h1>当前计数 : {counter}</h1></div>);
}
4. React变量使用
JSX嵌入变量作为子元素
情况一 : 直接显示
当变量是Number、String、Array类型时,可以直接显示
class App extends React.Component {constructor() {super();this.state = {// Number/String/Array => 直接显示num: 10,str: 'abc',arr: [1, 2, 3],};}render() {// 直接显示const { num, str, arr } = this.state;return (<div>{/* Number/String/Array => 直接显示,其中Array会依次拿出元素遍历出来 */}<h1>{num}</h1><h1>{str}</h1><h1>{arr}</h1></div>);}
}
情况二 : 不显示
当变量是null、undefined、Boolean类型时,内容为空
ps : 如果希望可以显示null、undefined、Boolean,那么需要转成字符串
class App extends React.Component {constructor() {super();this.state = {// null/undefined/boolean => 页面不显示aa: null,bb: undefined,cc: true,dd: false};}render() {// 页面不显示const { aa, bb, cc, dd } = this.state;return (<div>{/* null/undefined/boolean => 界面上不显示,也不会报错*/}<h2>{aa}</h2><h2>{bb}</h2><h2>{cc}</h2><h2>{dd}</h2>{/* 可以转成字符串显示出来 */}<h2>{aa + ''}</h2><h2>{String(bb)}</h2><h2>{cc.toString()}</h2></div>);}
}
情况三: Object对象类型不能作为子元素
Object对象类型不能作为子元素(not valid as a React child)
class App extends React.Component {constructor() {super();this.state = {// Object类型,不能作为子元素显示,报错obj: {name: 'coder',age: 18}};}render() {// Object类型,不能作为子元素显示,报错const { obj } = this.state;return (<div>{/* Object类型,不能作为子元素显示,报错 */}{/* <h3>{obj}</h3> */}{/* Object中的属性可以 */}<h3>{obj.name}</h3><h3>{obj.age}</h3></div>);}
}
JSX嵌入表达式
运算表达式
render() {const firstName = 'coder';const lastName = 'star';return (<div><h1>{1 + 2}</h1><h1>{firstName + lastName}</h1></div>);
}
三元运算符
render() {const boo = true;const age = 18;return (<div><h1>{age >= 18 ? '成年' : '未成年'}</h1><h1>{boo ? 'true' : 'false'}</h1></div>);
}
执行函数
// 抽离出来,在函数中做复杂的操作
getName = () => {return 'abc' + 'sdfs' + 'we';
};render() {return (<div><h1>{this.getName()}</h1></div>);
}
JSX绑定属性
render() {const title = 'title';const imgUrl = 'https://n.sinaimg.cn/sinakd10111/533/w533h800/20200713/6340-iwhseit8630287.jpg';return (<div><h2 title={title}></h2><img src={imgUrl} /></div>);
}
JSX绑定类Class
绑定class属性 : 最好使用className
写法一 : 字符串拼接
render() {const isActive = false;return (<div><h2 className='a b'>111</h2>{/* 动态绑定class */}<h2 className={`a b c ${isActive ? 'active' : ''}`}>222</h2></div>);
}
写法二 : 放入数组中
render() {const isActive = true;const classList = ['a', 'b'];isActive && classList.push('active');return (<div><h2 className='a b'>111</h2>{/* 动态绑定class */}<h2 className={classList.join(' ')}>222</h2></div>);
}
写法三 : 插件 - classnames
脚手架中使用该插件 => npm insatall classnames
JSX绑定样式Style
render() {const style = { color: 'blue', fontSize: '26px' };return (<div>{/* 1. 不支持 */}{/* <h2 style='color:red'>111</h2>*/}{/* 2. { {中间是对象} } */}<h2 style={{ color: 'red', fontSize: '26px' }}>111</h2>{/* 3. { {中间是对象} } */}<h2 style={style}>222</h2></div>);
}
5. React事件绑定
this的绑定问题
事件绑定中的this默认情况下是undefined
-
很奇怪,居然是undefined
-
因为在正常的DOM操作中,监听点击,监听函数中的this其实是节点对象 -比如说是button对象
-
这次因为React并不是直接渲染成真实的DOM,我们所编写的button只是一个语法糖,它的本质React的Element对象
-
那么在这里发生监听的时候,react在执行函数时并没有绑定this,默认情况下就是一个undefined
-
onClick = {this.fn} => 这个时候函数还没有执行,调用的时候可能是默认调用
this问题
因其内部很可能是默认调用,如果不传递this进去,在严格模式下,方法内部的this就为undefined,所以通过bind绑this进去,不管后面怎么调用,this都为绑定的this
写法一 : 传入函数时绑定this
<script type="text/babel">// 封装类组件class App extends React.Component {// 1. 组件数据constructor() {super();// 动态的数据,需要放在这里!this.state = {message: 'hello world'};}// 2. 组件方法( 实例方法 )btnClick() {/* this为undefined => this.btnClick* 需要绑定this过来 => this.btnClick.bind(this)*/// 修改数据 this.setState为继承类里面的方法/* 内部完成了两件事情* 1. 将state中的message的值修改掉* 2. 自动重新执行render函数*/this.setState({message: 'hello react'});}// 3. 渲染内容 render 方法render() {console.log(this); // 这里有当前的实例return (<div><h2>{this.state.message}</h2><button onClick={this.btnClick.bind(this)}>修改文本</button></div>);}}// 将组件渲染到界面上const root = ReactDOM.createRoot(document.querySelector('#root'));root.render(<App />);
</script>
写法二 : constructor中绑定好this
<script type="text/babel">// 封装类组件class App extends React.Component {constructor() {super();this.state = {message: 'hello world'};/* 这里绑定好*/// 为了在回调中使用 `this`,这个绑定是必不可少的this.btnClick = this.btnClick.bind(this);}btnClick() {this.setState({message: 'hello react'});}render() {// 这里就不用再次绑定了return (<div><h2>{this.state.message}</h2><button onClick={this.btnClick}>修改文本</button></div>);}}// 将组件渲染到界面上const root = ReactDOM.createRoot(document.querySelector('#root'));// APP 根组件root.render(<App />);
</script>
写法三 : 函数使用箭头函数
使用箭头函数 : 箭头函数中没有this,自动去上层作用域中找到this
<script type="text/babel">// 封装类组件class App extends React.Component {constructor() {super();this.state = {message: 'hello world'};}/* 使用箭头函数 : 也没有问题!*/btnClick = () => {this.setState({message: 'hello react'});};render() {return (<div><h2>{this.state.message}</h2><button onClick={this.btnClick}>修改文本</button></div>);}}// 将组件渲染到界面上const root = ReactDOM.createRoot(document.querySelector('#root'));root.render(<App />);
</script>
写法四 : 直接传入箭头函数 ( 推荐 )
<script type="text/babel">// 封装类组件class App extends React.Component {constructor() {super();this.state = {message: 'hello world'};}btnClick() {console.log(this);this.setState({message: 'hello react'});}render() {return (<div><h2>{this.state.message}</h2>{/* 直接使用箭头函数* 当点击时候,执行箭头函数,然后执行btnClick,这里就是隐式绑定了*/}<button onClick={() => this.btnClick()}>修改文本</button></div>);}}// 将组件渲染到界面上const root = ReactDOM.createRoot(document.querySelector('#root'));root.render(<App />);
</script>
事件参数传递
event参数
class App extends React.Component {constructor() {super();}btnClick(e) {console.log('btnClick', this, e);}render() {return (<div>{/* 方式一 : 有事件参数,没有this */}<button onClick={this.btnClick}>按钮</button>{/* 方式二 : 有事件参数,有this */}<button onClick={this.btnClick.bind(this)}>按钮</button>{/* 方式三 : 须手动传递下事件参数,有this */}<button onClick={(e) => this.btnClick(e)}>按钮</button></div>);}
}
传递额外参数
class App extends React.Component {constructor() {super();}/* 记住顺序,event是在最后* bind的时候把前两个参数传递过来了* 调用的时候,event才传过来*/btnClick(name, age, event) {console.log('btnClick', name, age, event);}render() {return (<div>{/* 方式一 : 传递参数需要记住顺序 */}<button onClick={this.btnClick.bind(this, 'coder', 18)}>按钮</button>{/* 方式二 : 传递参数时,很清晰 */}<button onClick={(e) => this.btnClick('star', 17, e)}>按钮</button></div>);}
}
案例
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><script src="./lib/react.js"></script><script src="./lib/react-dom.js"></script><script src="./lib/babel.js"></script><style>.active {color: blue;}</style></head><body><div id="root"></div><script type="text/babel">/* 创建App组件*/class App extends React.Component {constructor() {super();this.state = {movies: ['海绵宝宝', '派大星', '章鱼哥', '蟹老板'],currentIndex: 0};}itemClick(index) {this.setState({currentIndex: index})}render() {const { movies, currentIndex } = this.state;return (<div><ul>{movies.map((item, index) => {return (<li className={currentIndex === index ? 'active' : ''}key={item}onClick={() => this.itemClick(index)}>{item}</li>);})}</ul></div>);}}/* 创建根组件并渲染*/const root = ReactDOM.createRoot(document.querySelector('#root'));root.render(<App />);</script></body>
</html>
6. React条件渲染
方式一 : 使用if判断
适合 逻辑较多 的情况

方式二 : 三元运算符
适合 逻辑比较简单 的情况

方式三:&& - 与运算符
适合如果条件成立,渲染某一个组件;如果条件不成立,什么内容也不渲染

方式四:v-show的效果

案例
<script type="text/babel">/* 创建App组件*/class App extends React.Component {constructor() {super();this.state = {isShow: true};}tabClick() {this.setState({isShow: !this.state.isShow});}render() {const { isShow } = this.state;return (<div><button onClick={() => this.tabClick()}>切换</button>{isShow && <h2>我显示了</h2>}<h2 style={{ display: isShow ? 'block' : 'none' }}>我也来!</h2></div>);}}/* 创建根组件并渲染*/const root = ReactDOM.createRoot(document.querySelector('#root'));root.render(<App />);
</script>
7. React列表渲染
render - 写法一
使用for循环
render() {// 1. 创建元素数组const elList = [];for (let i = 0; i < this.state.list.length; i++) {const movies = this.state.list[i];// 2. 创建li元素const el = <li key={i}>{movies}</li>;// 3. 推入元素数组中elList.push(el);}return (// 4. 直接放入数组<ul>{elList}</ul>);
}
render - 写法二
使用map循环 : 展示列表最多的方式就是使用数组的map高阶函数
render() {return (// 循环<ul>{this.state.list.map((item) => {return <li key={item}>{item}</li>;})}</ul>);
}
三、JSX的本质和原理
1. 概念
实际上,jsx 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖
所有的jsx最终都会被转换成React.createElement的函数调用
createElement需要传递三个参数:
-
参数一:type
-
当前ReactElement的类型
-
如果是标签元素,那么就使用字符串表示 “div”
-
如果是组件元素,那么就直接使用组件的名称
-
参数二:config
-
所有jsx中的属性都在config中以对象的属性和值的形式存储
-
比如传入className作为元素的class
-
参数三:children
-
存放在标签中的内容,以children数组的方式进行存储
-
如果是多个元素,React内部有对它们进行处理
2. createElement源码

3. 在Babel官网查看

4. 直接编写jsx代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><script src="./lib/react.js"></script><script src="./lib/react-dom.js"></script><!-- 不使用babel --><!-- <script src="./lib/babel.js"></script> --></head><body><div id="root"></div><!-- 不使用babel --><!-- <script type="text/babel"> --><script>/* 创建App组件*/class App extends React.Component {constructor() {super();this.state = {counter: 10};}render() {const { counter } = this.state;const ele = /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {className: "header"}, "header"), /*#__PURE__*/React.createElement("div", {className: "main"}, /*#__PURE__*/React.createElement("ul", {className: "nav"}, /*#__PURE__*/React.createElement("li", {className: "item"}, "1"), /*#__PURE__*/React.createElement("li", {className: "item"}, "2"), /*#__PURE__*/React.createElement("li", {className: "item"}, "3"), /*#__PURE__*/React.createElement("li", {className: "item"}, "4"), /*#__PURE__*/React.createElement("li", {className: "item"}, "5"))), /*#__PURE__*/React.createElement("div", {className: "footer"}, "footer"));return ele}}/* 创建根组件并渲染*/const root = ReactDOM.createRoot(document.querySelector('#root'));// root.render(React.createElement(App, null));</script></body>
</html>
5. 虚拟DOM
01 - 虚拟DOM创建过程
-
通过 React.createElement 最终创建出来一个 ReactElement对象
-
React利用ReactElement对象组成了一个JavaScript的对象树
-
JavaScript的对象树就是虚拟DOM(Virtual DOM)

02 - 虚拟DOM的作用
-
1. 在更新数据时不会把整一段全部重新渲染
-
会在新旧虚拟dom之间进行diff算法计算,然后再重新渲染有差别的部分
-
2. 跨平台,使用React-native原生开发
-
虚拟DOM就是js对象,ReactElement对象
-
可根据环境不同,桥接到环境时,生成不同的东西
-
web端 => div、button IOS、Android端 => 原生控件、view、...
-
3. 从命令式编程转到了声明式编程的模式
6. jsx – 虚拟DOM – 真实DOM

7. 声明式编程
虚拟DOM帮助我们从命令式编程转到了声明式编程的模式
React官方的说法:
-
Virtual DOM 是一种编程理念
-
在这个理念中,UI以一种理想化或者说虚拟化的方式保存在内存中,并且它是一个相对简单的JavaScript对象
-
可以通过root.render让 虚拟DOM 和 真实DOM同步起来,这个过程中叫做协调
这种编程的方式赋予了React声明式的API :
-
只需要告诉React希望让UI是什么状态
-
React来确保DOM和这些状态是匹配的
-
不需要直接进行DOM操作,可以从手动更改DOM、属性操作、事件处理中解放出来
四、React脚手架
1. 概念
01 - 脚手架
脚手架 : 让项目从搭建到开发,再到部署,整个流程变得快速和便捷
现在比较流行的三大框架都有属于自己的脚手架:
-
Vue的脚手架:@vue/cli
-
Angular的脚手架:@angular/cli
-
React的脚手架:create-react-app
02 - 安装node
网址 : Node.js
2. React项目
01 - 安装脚手架
npm install create-react-app -g
// 查看安装的版本
create-react-app --version
02 - 创建项目
-
项目名称不能包含大写字母
-
create-react-app 项目名称
03 - 运行项目
npm run start
04 - 目录结构分析

3. webpack配置
如果希望看到webpack的配置信息,
可以执行命令 =>package.json文件中的一个脚本:"eject": "react-scripts eject"
这个操作是不可逆的

4. 删除项目结构
-
将src下的所有文件都删除
-
将public文件下出列favicon.ico和index.html之外的文件都删除掉

5. 开始编写代码
01 - 在src下创建 index.js
/* 入口文件*/
// react18 从这里引入ReactDOM
import ReactDOM from 'react-dom/client';import App from './App.jsx';const root = ReactDOM.createRoot(document.querySelector('#root'));/* <App /> => 这里实际上就是App类的实例,相当于创建了一个实例*/
root.render(<App />);
02 - 在src下创建 App.jsx
/* 内部有单独导出Component* import React from 'react';* import { Component } from 'react';* 所以可以合并*/import React, { Component } from 'react';class App extends React.Component {constructor() {super();this.state = {};}render() {return (<div><h2>title</h2></div>);}
}// 导出类
export default App