1、React简介
React 是一个用于构建用户界面的 JAVASCRIPT 库。
React 主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图)。
React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。
React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使用它。
2、React的写法
简单示例
- render方法注意点
- 多次渲染, 后渲染会覆盖先渲染
- render方法一次只能渲染一个元素/组件 - createElement方法注意点
- 可以添加3个以上参数, 后续参数都会作为当前创建元素内容处理 - 如何给元素添加监听?
- 给元素添加监听的本质就是给元素添加属性
所以可以在createElement()的第二个参数中添加
- <button onclick="btnClick">按钮</button>
- React.createElement(‘button’, {onClick: btnClick}, ‘按钮’);
注意事项:
如果想给元素绑定事件, 那么事件名称必须是驼峰命名
<body>
<div id="app"></div>
</body>
<script>
let name = '老王';
let oDiv = React.createElement('div', null, name)
let oBtn = React.createElement('button', null, '点击')
//点击事件2个元素都会触发
let root = React.createElement('div', {
onClick: fn
}, oDiv, oBtn)
ReactDOM.render(root, document.querySelector('#app'), () => {
console.log('全部渲染');
})
function fn() {
console.log('打印了');
}
</script>
3、JSX写法
3.1、通过createElement创建元素存在的问题?
- 如果结构比较简单还好, 但是如果结构比较复杂, 就比较难以下手
所以大牛们就发明了JSX, 专门用来编写React中的页面结构体
3.2、什么是JSX?
- JSX === JavaScript + X === (XML) === (eXtension)
- JSX 是一个看起来很像 XML 的 JavaScript 语法扩展
3.3、为什么要使用JSX?
- 使用JSX使得我们在React中编写页面结构更为简单、灵活
- JSX 是类型安全的,在编译过程中就能发现错误
- JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化
- 防止XSS注入攻击
3.4、JSX本质?
- 浏览器只认识JS不认识JSX, 所以我们编写的JSX代码是无法在浏览器中执行的
- 为了解决这个问题, 我们需要借助babel将JSX转换成JS, 也就是转换成React.createElement();
3.5、如何在项目中将JSX转换成JS?
- 导入babel.js
- 在script标签上添加type=”text/babel”
<script src="./react17/react.development.v17.js"></script>
<script src="./react17/react-dom.development.v17.js"></script>
<script src="./react17/babel.min.js"></script>
<body>
<div id="app"></div>
</body>
<script type="text/babel">
let name = "老王";
let myRoot = (
<div>
<div>{name}</div>
<button onClick={fn}>点击</button>
</div>
);
ReactDOM.render(myRoot, document.querySelector("#app"), () => {
console.log("创建成功");
});
function fn() {
console.log("输出");
}
</script>
4、函数组件
4.1、在React中如何定义组件?
- 在React中创建组件有两种方式
- 第一种: 通过ES6之前的构造函数来定义(无状态组件)
- 第二种: 通过ES6开始的class来定义(有状态组件)
4.2、如何通过ES5的构造函数来定义组件
- 在构造函数中返回组件的结构即可
<script type="text/babel">
let name = "老王";
function Wang() {//通过构造函数来创建组件
return (
<div>
<div>{name}</div>
<button onClick={fn}>点击</button>
</div>
);
}
ReactDOM.render(<Wang />, document.querySelector("#app"), () => {
console.log("创建成功");
});
function fn() {
console.log("按钮");
}
</script>
5、类组件
如何通过ES6的class来定义组件
- 定义一个类, 在这个类中实现render方法, 在render方法中返回组件的结构即可
<script type="text/babel">
let name = "老王";
class Wang extends React.Component {//通过class来创建组件
render() {
return (
<div>
<div>{name}</div>
<button onClick={fn}>点击</button>
</div>
);
}
}
ReactDOM.render(<Wang />, document.querySelector("#app"), () => {
console.log("创建成功");
});
function fn() {
console.log("点击了");
}
</script>
6、有状态组件和无状态组件的区别
6.1、有状态组件和无状态组件?
- 首先需要明确的是, 组件中的状态(state)指的其实就是数据
+ 有状态组件指的就是有自己数据的组件(逻辑组件)
+ 无状态组件指的就是没有自己数据的组件(展示组件)
6.2、如何定义自己的状态?
- 凡是继承于React.Component的组件, 默认都会从父类继承过来一个state属性
这个state属性就是专门用来保存当前数据的
- 所以但凡是继承于React.Component的组件, 都是有状态组件
- 所以但凡不是继承于React.Component的组件, 都是无状态组件
- 所以类组件就是有状态组件
- 所以函数组件就是无状态组件
<script type="text/babel">
let name = "老王";
// function WANG(){
// return(
// <div>
// <div>{state + name}</div>
// {
// //会返回state is not defined
// }
// <button onClick={fn}>点击</button>
// </div>
// )
// }
// ReactDOM.render(<WANG />, document.querySelector("#app"), () => {
// console.log("创建成功");
// });
class Wang extends React.Component {
render() {
return (
<div>
<div>{this.state + name}</div>
{
//视图会显示出null老王,代表确实有state,但是现在值为null
}
<button onClick={fn}>点击</button>
</div>
);
}
}
ReactDOM.render(<Wang />, document.querySelector("#app"), () => {
console.log("创建成功");
});
function fn() {
console.log("点击了");
}
</script>
7、setState的用法
state属性注意点
- 永远不要直接修改state
- 直接修改state并不会触发界面更新
- 只有使用setState方法修改state才会触发界面更新
<script type="text/babel">
class Wang extends React.Component {
constructor() {
super();
this.state = {
name: "老王",
age: 18, //类似于vue中data,用于存放静态数据的
};
}
render() {
return (
<div>
<div>姓名{this.state.name}</div>
<div>年龄{this.state.age}</div>
<button onClick={()=>this.fn(this.state.age)}>点击</button>
</div>
);
}
fn = (val) => {
// this.state.age=20
console.log('原生的值',val);
// console.log('修改的值',this.state.age);//state中值确实被修改,但是视图不会被改变
this.setState({
age:21
})
setTimeout(()=>{//需要通过异步的方式才能获取到新值,因为setState常规情况是异步的
console.log(this.state.age);
},200)
};
}
ReactDOM.render(<Wang />, document.querySelector("#app"), () => {
console.log("创建成功");
});
</script>
8、this指向
8.1、this指向问题
- 在ES6之前, 方法中的this谁调用就是谁,
并且还可以通过call/apply/bind方法修改this
- 从ES6开始, 新增了箭头函数, 箭头函数没有自己的this,
箭头函数中的this是函数外最近的那个this
并且由于箭头函数没有自己的this, 所以不能通过call/apply/bind方法修改this
8.2、监听事件中的this
- React内部在调用监听方法的时候, 默认会通过apply方法将监听方法的this修改为了undefined
所以在监听方法中无法通过this拿到当前组件的state. (undefined.state)
- 如果想在监听方法中拿到当前组件的state, 那么就必须保证监听方法中的this就是当前实例
所以我们可以借助箭头函数的特性, 让React无法修改监听方法中的this, 让监听方法中的this就是当前实例
<script type="text/babel">
class Wang extends React.Component {
constructor() {
super();
this.state = {
name: "老王",
age: 18, //类似于vue中data,用于存放静态数据的
};
}
render() {
return (
<div>
<div>{this.state.name}</div>
<button onClick={()=>{this.fn(this.state.age)}}>点击</button>
</div>
);
}
fn = (val) => {
//相当于用变量接收一个匿名的箭头函数
console.log("点击了",val);
};
}
ReactDOM.render(<Wang />, document.querySelector("#app"), () => {
console.log("创建成功");
});
</script>
8.3、测试:
import React from 'react';
const STR = '被调用,this指向:';
class App extends React.Component{
constructor(){
super()
}
//测试函数
handler() {
console.log(`handler ${STR}`,this);
}
render(){
console.log(`render ${STR}`,this);
return(
<div>
<h1>hello World</h1>
<label htmlFor = 'btn'>单击打印函数handler中this的指向</label>
<input id = "btn" type="button" value = '单击' onClick = {this.handler}/>
</div>
)
}
}
export default App