React系统学习:从基础语法到虚拟DOM

2970 字
15 分钟
React系统学习:从基础语法到虚拟DOM

📝 本文基于作者学习笔记,系统整理了 React 基础知识,适合前端开发者入门参考。

react是facebook开源的,为什么高效的原因,是因为使用了虚拟dom技术,可以很大程度的复用。

1.基本语法#

helloWorld,babel的引入是为了将jsx转换为js,使用jsx可以更快的创建虚拟dom。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello_react</title>
</head>
<body>
<div id="test"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
const VDOM = <h1>hello,React</h1>
ReactDOM.render(VDOM,document.getElementById('test')) /*此处不写引号,不是字符串*/
</script>
</body>
</html>

JSX的基本语法:

  • 定义虚拟DOM时,不要写引号
  • 标签中混入JS表达式要用{},注意用const xxx=可以接收的才叫表达式
  • 样式的类名指定不要用class,要用className
  • 内联样式,要用style={{key}}形式
  • 只有一个根标签
  • 标签必须闭合
  • 标签首字母: (1)若小写字母开头,则把标签转化为html同名元素,若没有对应同名元素则报错 (2)若大写字母开头,react就去渲染对应的组件,若组件没有定义则报错。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello_react</title>
</head>
<style>
.title {
font-size: large;
color: blue;
}
</style>
<body>
<div id="test"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
const title = 'title'
const VDOM = (
<div>
<h1 className={title} style={{ color: 'red' }}>
<span>hello,React</span>
</h1>
<Good></Good>
</div>
)
ReactDOM.render(VDOM, document.getElementById('test')) /*此处不写引号,不是字符串*/
</script>
</body>
</html>

2.面向组件编程#

js的模块化只是拆分html,而组件编程则是html、css、js、img、video等整合起来是一个组件,优点是复用编码,提高效率。

2.1函数式组件#

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>hello_react</title>
</head>
<style>
.title {
font-size: large;
color: blue;
}
</style>
<body>
<div id="test"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script
type="text/javascript"
src="../js/react-dom.development.js"
></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
function Demo() {
return <h1>我是一个函数式组件(适用于简单的自定义)</h1>;
}
ReactDOM.render(<Demo />, document.getElementById("test"));
</script>
</body>
</html>

2.2类式组件#

2.2.1类的初识#

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>hello_react</title>
</head>
<style>
.title {
font-size: large;
color: blue;
}
</style>
<body>
<div id="test"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script
type="text/javascript"
src="../js/react-dom.development.js"
></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
// 创建一个Person类
class Perseon {
// 构造器方法
constructor(name, age) {
this.name = name;
this.age = age;
}
// 一般方法
speak() {
// speak方法在类的原型对象上,供实例使用
// 通过Person实例调用speak时,speak中的this就是Person实例
console.log(`我叫${this.name},我已经${this.age}了`);
}
}
class Student extends Perseon {
constructor(name, age, grade) {
// 子类使用构造器一定要使用super且必须在前面
super(name, age);
this.grade = grade;
}
// 重写父类继承的方法
speak(name,age,grade){
console.log(`我叫${this.name},我已经${this.age}了,在读${this.grade}`);
}
}
const mm = new Perseon("小满", 10);
console.log(mm);
mm.speak();
// call可以更改函数里的this指向
mm.speak.call({ name: "didi", age: 8 });
const ls = new Student("李四", "18", "大一");
ls.speak();
</script>
</body>
</html>

2.2.2使用#

React解析组件标签时,发现组件是使用类定义的,会new出该类实例,并通过该实例调用到原型上的render

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>hello_react</title>
</head>
<style>
.title {
font-size: large;
color: blue;
}
</style>
<body>
<div id="test"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script
type="text/javascript"
src="../js/react-dom.development.js"
></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
class MyComponent extends React.Component{
render(){
return '我是一个类式组件'
}
}
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
</script>
</body>
</html>

3.State状态#

借助构造器初始化状态并使用,通过点击事件修改状态。

3.1标准写法(强制绑定)#

下面是标准写法,借助构造器的this对state进行初始化

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>hello_react</title>
</head>
<style>
.title {
font-size: large;
color: blue;
}
</style>
<body>
<div id="test"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script
type="text/javascript"
src="../js/react-dom.development.js"
></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
class Weather extends React.Component {
constructor(props) {
super(props);
// 初始化状态
this.state = { isHot: true, wind: "微风" };
// 解决changeWeather中指向问题
this.changeWeather = this.changeWeather.bind(this);
}
render() {
const { isHot, wind } = this.state;
return (
<h1 onClick={this.changeWeather}>
今天天气{isHot ? "炎热" : "凉爽"}{wind}
</h1>
);
}
changeWeather() {
const isHot = this.state.isHot;
this.setState({ isHot: !isHot });
console.log("修改天气:", this.state.isHot);
}
}
ReactDOM.render(<Weather />, document.getElementById("test"));
</script>
</body>
</html>

React State状态示例:天气炎热与凉爽切换
React State状态示例:天气炎热与凉爽切换

点击切换State状态后的效果
点击切换State状态后的效果

3.2简化写法(箭头函数)#

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>hello_react</title>
</head>
<style>
.title {
font-size: large;
color: blue;
}
</style>
<body>
<div id="test"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script
type="text/javascript"
src="../js/react-dom.development.js"
></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
class Weather extends React.Component {
// 自定义状态
state = { isHot: true, wind: "微风" };
render() {
const { isHot, wind } = this.state;
return (
<h1 onClick={this.changeWeather}>
今天天气{isHot ? "炎热" : "凉爽"}{wind}
</h1>
);
}
// 自定义方法——用赋值语句+箭头函数的形式
changeWeather = () => {
console.log(this);
const isHot = this.state.isHot;
this.setState({ isHot: !isHot });
console.log("修改天气:", this.state.isHot);
};
}
ReactDOM.render(<Weather />, document.getElementById("test"));
</script>
</body>
</html>

4.props多种属性#

三点运算符…表示展开,是对于一个数组。

4.1基本使用#

{...Person}在原生es6语法中表示克隆一个对象
{...Person,name:'jack'}表示克隆一个对象并替换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>hello_react</title>
</head>
<body>
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script
type="text/javascript"
src="../js/react-dom.development.js"
></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
class Weather extends React.Component {
render() {
const { area, day, weather } = this.props;
return (
<ul>
<li>{area}</li>
<li>{day}</li>
<li>{weather}</li>
</ul>
);
}
}
const p = { area: "福州", day: "11月25日", weather: "晴" };
//这里不是表示克隆而是展开p,因为react+babel,原生会报错,而且只有标签属性可以
ReactDOM.render(<Weather {...p} />, document.getElementById("test1"));
ReactDOM.render(
<Weather area="泉州" day="11月25日" weather="阴" />,
document.getElementById("test2")
);
ReactDOM.render(
<Weather area="厦门" day="11月25日" weather="大风" />,
document.getElementById("test3")
);
</script>
</body>
</html>

4.2标签属性限制#

Person.propTypes = {
name: PropTypes.string.isRequired,//限制name必传,且为字符串
sex: PropTypes.string,//限制sex为字符串
age: PropTypes.number,//限制age为数值
speak:PropTypes.func//限制speak为函数
};
Person.defaultProps = {
sex: "保密",//sex默认值保密
};

4.3简写#

class Person extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired, //限制name必传,且为字符串
sex: PropTypes.string, //限制sex为字符串
age: PropTypes.number, //限制age为数值
speak: PropTypes.func, //限制speak为函数
};
static defaultProps = {
sex: "保密", //sex默认值保密
};
render() {
const { name, sex, age } = this.props;
return (
<ul>
<li>{name}</li>
<li>{sex}</li>
<li>{age + 1}</li>
</ul>
);
}
}

5.refs#

在 React 中,refs 是用来访问和操作 DOM 元素或组件实例的一种方式。通过 refs,开发者可以直接与 DOM 进行交互,而无需依赖 React 的状态管理和生命周期方法。

5.1字符串形式#

class Demo extends React.Component {
showData = () => {
console.log(this);
const {input1} = this.refs
console.log(input1.value);
};
render() {
return (
<div>
<input ref="input1" type="text" placeholder="点击按钮提示数据" />
&nbsp;
<button onClick={this.showData}>获取数据</button>&nbsp;
<input id="input2" placeholder="失去焦点提示数据" />
</div>
);
}
}
ReactDOM.render(<Demo />, document.getElementById("test1"));

5.2回调函数形式#

<script type="text/babel">
class Demo extends React.Component {
showData = () => {
const { input1 } = this.refs;
console.log(this.input1.value);
};
render() {
return (
<div>
<input
ref={(c) => (this.input1 = c)}
type="text"
placeholder="点击按钮提示数据"
/>
&nbsp;
<button onClick={this.showData}>获取数据</button>&nbsp;
</div>
);
}
}
ReactDOM.render(<Demo />, document.getElementById("test1"));
</script>

5.3createRef形式#

myRef1 = React.createRef();
<input
ref={this.myRef1}
type="text"
placeholder="点击按钮提示数据"
/>
<script type="text/babel">
class Demo extends React.Component {
state = { isHot: true };
myRef1 = React.createRef();
myRef2 = React.createRef();
showData = () => {
console.log(this.myRef1.current.value);
};
showData2 = () => {
alert(this.myRef2.current.value);
};
changeWeather = () => {
const { isHot } = this.state;
this.setState({ isHot: !isHot });
};
render() {
const { isHot } = this.state;
return (
<div>
<h1>今天天气很{isHot ? "炎热" : "凉爽"}</h1>
<input
ref={this.myRef1}
type="text"
placeholder="点击按钮提示数据"
/>
&nbsp;
<button onClick={this.showData}>获取数据</button>
&nbsp;
<button onClick={this.changeWeather}>点击切换天气</button>&nbsp;
<input
onBlur={this.showData2}
ref={this.myRef2}
type="text"
placeholder="失去焦点提示数据"
/>
&nbsp;
</div>
);
}
}
ReactDOM.render(<Demo />, document.getElementById("test1"));
</script>

6.react中的事件处理#

不要过度使用ref,如果发生事件的元素就是你要操作的元素的时候就可以不适用ref。

//使用ref的版本
showData2 = () => {
alert(this.myRef2.current.value);
};
<input nBlur={this.showData2}
ref={this.myRef2}
type="text"
placeholder="失去焦点提示数据"
/>
//不使用ref的版本
showData2 = (event) => {
alert(event.target.value);
};
<input nBlur={this.showData2}
type="text"
placeholder="失去焦点提示数据"
/>

7.react中收集表单数据#

优先使用受控组件,因为使用非受控组件需要使用ref

7.1非受控组件#

现用现取属于非受控

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>hello_react</title>
</head>
<body>
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script
type="text/javascript"
src="../js/react-dom.development.js"
></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
class Login extends React.Component {
handleSubmit = (event) => {
event.preventDefault();
const { username, password } = this;
alert(`你输入的用户名是${username.value},密码是${password.value}`);
};
render() {
return (
<form action="http://www.baidu.com" onSubmit={this.handleSubmit}>
用户名:
<input
type="text"
ref={(c) => (this.username = c)}
name="username"
/>
密码:
<input
type="password"
ref={(c) => (this.password = c)}
name="password"
/>
<button>登陆</button>
</form>
);
}
}
ReactDOM.render(<Login />, document.getElementById("test1"));
</script>
</body>
</html>

7.2受控组件#

页面中所有输入类的dom,随着输入可以维护到状态中,需要使用的时候通过状态中读取。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>hello_react</title>
</head>
<body>
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script
type="text/javascript"
src="../js/react-dom.development.js"
></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
class Login extends React.Component {
// 初始化状态
state = {
username: "", //用户名
password: "", //密码
};
handleSubmit = (event) => {
event.preventDefault(); //阻止表单提交
const { username, password } = this.state;
alert(`你输入的用户名是${username},密码是${password}`);
};
saveUsername = (event) => {
this.setState({ username: event.target.value });
};
savePassword = (event) => {
this.setState({ password: event.target.value });
};
render() {
return (
<form onSubmit={this.handleSubmit}>
用户名:
<input type="text" name="username" onChange={this.saveUsername} />
密码:
<input
type="password"
name="password"
onChange={this.savePassword}
/>
<button>登陆</button>
</form>
);
}
}
ReactDOM.render(<Login />, document.getElementById("test1"));
</script>
</body>
</html>

*8.生命周期#

下面是一副生命周期的流程,挂载比较简单就是一直往下走;setState就是先往左再往下;forceUpdate也是先往左再往下

React组件生命周期流程图
React组件生命周期流程图

初始化阶段:由ReactDOM.render()触发---初次渲染

  1. constructor()
  2. componentWillMount()
  3. render()
  4. componentDidMount() ===> 常用,一般在钩子里做初始化操作,例如:开定时器,发网络请求,订阅消息

更新阶段:由组件内部this.setState()或父组件render触发

  1. shouldComponentUpdate()
  2. componentWillUpdate()
  3. render() ==> 必须使用一个
  4. componentDidUpdate()

卸载组件:由ReactDOM.unmountComponentAtNode()触发

  1. componentWillUnmount ==>常用,一般做收尾动作,例如:关闭定时器取消订阅
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>生命周期</title>
</head>
<body>
<div id="test"></div>
<!-- 先引入核心库、扩展库、babel库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<script
type="text/javascript"
src="../js/react-dom.development.js"
></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
// 创建组件
// 生命周期回调函数<==>生命周期钩子函数<==>生命周期钩子<==>生命周期函数
class Count extends React.Component {
// 构造器
constructor(props) {
console.log("Count---constructor");
super(props);
this.state = { count: 0 };
}
add = () => {
const { count } = this.state;
this.setState({ count: count + 1 });
};
// 卸载组件按钮回调
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById("test"));
};
force = () => {
this.forceUpdate();
};
// 组件将要挂载的钩子
componentWillMount() {
console.log("Count---componentWillMount");
}
// 组件挂载完毕的钩子
componentDidMount() {
console.log("Count---componentDidMount");
}
// 组件将要卸载的钩子
componentWillUnmount() {
console.log("Count---componentWillUnmount");
}
// 控制组件更新的“阀门”
shouldComponentUpdate() {
console.log("Count---shouldComponentUpdate");
return true;
}
// 组件将要更新的钩子
componentWillUpdate() {
console.log("Count---componentWillUpdate");
}
// 组件更新完毕的钩子
componentDidUpdate() {
console.log("Count---componentDidUpdate");
}
render() {
console.log("render");
const { count } = this.state;
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={this.add}>点我加1</button>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>不更改任何状态,强制更新</button>
</div>
);
}
}
class A extends React.Component {
state = { carName: "奔驰" };
changeCar = () => {
this.setState({ carName: "奥迪" });
};
render() {
return (
<div>
<div>我是组件A</div>
<button onClick={this.changeCar}>换车</button>
<B carName={this.state.carName} />
</div>
);
}
}
class B extends React.Component {
componentWillReceiveProps(props) {
// 这个函数有坑,非首次更新才执行
console.log("B---componentWillReceiveProps");
}
render() {
return (
<div>
<div>我是B组件,接收到的车是{this.props.carName}</div>
</div>
);
}
}
ReactDOM.render(<A />, document.getElementById("test"));
</script>
</body>
</html>

相关推荐#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

React系统学习:从基础语法到虚拟DOM
https://blog.wmovie.site/posts/react-learning-guide/
作者
朵朵
发布于
2023-06-01
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
朵朵
全栈开发者,5 年 Java/SpringBoot + Vue/React 开发经验,曾维护 Delphi 遗留系统。业余深耕 NAS 与软路由,专注 Homelab 家庭网络搭建及 Docker 自托管应用实战。坐标福州,正迈向独立开发之路。
公告
欢迎来到我的博客!有什么想要的邮箱告诉我,最近沉迷nas和软路由。
分类
标签
站点统计
文章
25
分类
4
标签
18
总字数
32,908
运行时长
0
最后活动
0 天前

文章目录