React:用于构建用户界面的JS库
React的官方文档
声明式编程:
他允许我们只需要维护自己的状态,当状态改变时,React可以根据最新的状态去渲染我们的UI界面
组件化开发:将复杂的界面拆分成小的组件
多平台适配:
开发React必须依赖三个库:
<!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">
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<title>Hello React</title>
</head>
<body>
<div id="root"></div>
<div id="app"></div>
</body>
<script type="text/babel">
//渲染Hello World
//React18之前:ReactDom.render
// ReactDOM.render(hello world
,document.querySelector("#root"));
//react18之后:从一步变成了两步,可以创建多个根
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(<h2>hello root</h2>);
const app = ReactDOM.createRoot(document.querySelector("#app"));
app.render(<h2>hello app</h2>);
</script>
</html>
<body>
<div id="app"></div>
</body>
<script type="text/babel">
const app = ReactDOM.createRoot(document.querySelector("#app"));
//1.将文本定义成变量
let message = "Hello World"
//2.监听按钮的点击
function btnClick() {
console.log(1);
//1.1修改数据
message = "hello React";
//1.2重新渲染数据
rootRender();
}
//封装渲染函数
function rootRender(){
app.render((
<div>
<h2>{message}</h2>
<button onClick={btnClick}>修改文本</button>
</div>
));
}
//初始渲染一次
rootRender();
</script>
hello world案例可以看成一个整体,既然是整体,那么就可以将其封装成一个组件
组件中的数据分为两类:
btnClick
方法中的 this
将指向 undefined
或者是全局 window
对象,取决于是否在严格模式下。<body>
<div id="root"></div>
</body>
<script type="text/babel">
class App extends React.Component {
//组件数据
constructor() {
super();
this.state = {
message: "hello world"
}
//对需要绑定的方法,提前绑定好this,写在这里,只需绑定一次
this.btnClick = this.btnClick.bind(this)
}
//组件方法(实例方法)
btnClick() {
//如果button绑定方法时没有改变this的指向,严格模式下会指向undefinde。
//因为事件绑定过程中会执行类似 const click = this.btnClick;click(),这在babel的严格模式下会指向undefined
//所以我们需要将this指向数据所在的实例对象
console.log(this);
//父类的方法,内部完成了两件事情:1.将state中的message值修改掉,2.重新执行render方法
this.setState({
message: "hello react"
})
}
//渲染内容render方法
render() {
console.log("render:", this)//this指向当前组件实例
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={this.btnClick}>修改文本</button>
</div>
)
}
}
//this指向的问题
// const app = new App()
// const foo = app.btnClick()
// foo();//默认绑定 => window => 严格模式下 => undefined
// function bar() {
// console.log("bar:", this);默认绑定 => window => 严格模式下 => undefined
// }
// bar();
const root = ReactDOM.createRoot(document.querySelector("#root"));
//App可以作为一个根组件
root.render(<App />)
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=, initial-scale=1.0">
<script src="./lib/react.js"></script>
<script src="./lib/react-dom.js"></script>
<script src="./lib/babel.js"></script>
<title>Document</title>
</head>
<body>
<div id="root"></div>
</body>
<script type="text/babel">
//1创建root
const root = ReactDOM.createRoot(document.querySelector("#root"))
//创建组件
class App extends React.Component {
constructor() {
super()
this.state = {
movies: ["我爱你", "消失的她", "封神榜"]
}
}
render() {
//1.使用for循环
// const lis = []
// for(let i = 0;i
// const movie = this.state.movies[i];
// const li = {movie}
// lis.push(li);
// }
//2.使用map
const lis = this.state.movies.map(item=><li>{item}</li>)
return (
<div>
<h2>电影列表</h2>
<ul>
{lis}
</ul>
</div>
)
}
}
//写成 ,这是JSX语法,=React.createElement
root.render(<App/>)
</script>
</html>
<body>
<div id="root"></div>
</body>
<script type="text/babel">
const root = ReactDOM.createRoot(document.querySelector("#root"))
class App extends React.Component {
constructor() {
super();
this.state = {
counter: 100
}
this.increment = this.increment.bind(this)
this.decrement = this.decrement.bind(this)
}
increment() {
this.setState({
counter: this.state.counter + 1
})
}
decrement() {
this.setState({
counter: this.state.counter - 1
})
}
render() {
const { counter } = this.state
return (
<div>
<h2>{counter}</h2>
<button onClick={this.increment}>+1</button>
<button onClick={this.decrement}>-1</button>
</div>
)
}
}
root.render(<App />)
</script>
具体步骤:
const element =
这就是一段jsx语法(就是把html代码写到js当中),在js中会报错,因为js中不能直接给一个变量赋值html
render(){
const { message } = this.state
return(
{/* JSX的注释写法 */}
)
}
class App extends React.Component {
constructor() {
super();
this.state = {
a:10,
b:"string",
c:["1","2","3"],
d:undefined,
e:null,
f:true,
friend:{
name:"hhh"
}
}
}
render() {
const {a,b,c,d,e,f,friend} = this.state
return (
{/*number,string,array类型可以直接显示*/}
{a}
{b}
{c}
{/*undefined,null,boolean会被忽略,不显示,需要将其转换为字符串*/}
{d}
{e}
{f}
{/*将undefined,null,boolean转换为字符串*/}
{String(d)}
{e+""}
{f.toString()}
{/*object类型不能作为子元素显示 会报错*/}
{friend}
)
}
}
在执行map函数展示列表的时候,当我们没有向列表添加key时,会报错
btn1Click() {
console.log("btn1Click", this);
this.setState({
counter: 1
})
}
render() {
const { message, counter } = this.state
return (
{counter}
{/*1. this绑定方式一:bind绑定*/}
)
}
onClick={this.btn1Click}这里通过this.的方法调用,为什么不是隐式绑定?
因为这里并没有对btn1Click进行调用,只是引用
内部执行类似于:
React.createElement(“button”,{onClick:this.btn1Click})
const click = config.onClick
click()
* 所以我们需要通过bind改变this指向
我们模拟一下内部调用:
//模拟react中事件监听的执行
const app = {
foo: function () {
console.log("foo:", this)
}
}
const config = {
element: "button",
onClick: app.foo.bind(app)
}
const click = config.onClick
click();
三种this绑定方式的实例
class App extends React.Component {
constructor() {
super();
this.state = {
message: "hello world",
counter: 100
}
}
btn1Click() {
console.log("btn1Click", this);
this.setState({
counter: 1
})
}
btn2Click = () => {
console.log("btn2Click", this);
this.setState({
counter: 2
})
}
btn3Click() {
console.log("btn3Click", this);
this.setState({
counter: 3
})
}
render() {
const { message, counter } = this.state
return (
{counter}
{/*1. this绑定方式一:bind绑定*/}
{/*2. this绑定方式二:ES6 class fields*/}
{/*3. this绑定方式三:直接传入箭头函数
直接传入一个箭头函数,箭头函数的this指向执行上下文,
点击按钮时执行箭头函数,再用箭头函数调用btn3Click,隐式绑定this指向*/}
)
}
}
总而言之,多使用箭头函数