一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
大家好呀,我是L同学。最近在学习react,所以在接下来的文章中,我主要总结react的相关知识点。
需求介绍
我们先通过一个案例来介绍react的使用。
现在有个需求,就是点击按钮后,将文本从hello world变为hello react。我们先用原生代码实现,然后用react代码实现,看它们的区别。
原生代码实现
<body>
<h2 class="title"></h2>
<button class="btn">改变文本</button>
<script>
let message = 'hello world'
const titleEl = document.querySelector('.title')
// console.log(titleEl);
titleEl.innerHTML = message
const btnEl = document.querySelector('.btn')
btnEl.addEventListener('click', (e) => {
message = 'hello react'
titleEl.innerHTML = message
})
</script>
</body>
我们可以看到刚开始页面上显示的是hello world。点击按钮后,页面上显示的是hello react。
像这样子的原生代码,我们称之为命令式编程,也就是每做一个操作,都是给计算机(浏览器)一步步的命令。而Vue, React是声明式编程。
React实现
使用react开发,必须依赖3个库,分别是react、react-dom、babel。
- react: 包含了react所必须的核心代码。
- react-dom:react渲染在不同平台所需要的核心代码。针对不同的平台,web端和native端,react会渲染不同的东西。
- babel:将jsx(JavaScript XML)转换为react代码的工具。babel会将我们编写的jsx语法转换成React.createElement。
所以,我们先通过CDN引入这3个依赖。
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
我们先把hello world显示在页面上。
<body>
<div id="app">123</div>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
let message = 'hello world'
ReactDOM.render(<h2>{message}</h2>, document.querySelector('#app'))
</script>
</body>
这里需要注意的是,使用jsx,并且希望script中的jsx代码被babel解析,必须在script标签中添加一个属性type="text/babel"。
我们使用的ReactDOM,是react-dom这个库返回给我们的。ReactDOM.render函数接收两个参数。第一个参数是传递需要渲染的内容,可以是html元素,也可以是react组件。第二个参数是将渲染的内容挂载到哪个html元素上。在这个例子中,我们将h2元素挂载到id为app的div元素上。
现在页面上能显示hello world啦。
接下来,我们需要显示按钮,并且给按钮绑定点击事件。
<script type="text/babel">
let message = 'hello world'
function btnClick() {
message = 'hello react'
}
ReactDOM.render(
(
<div>
<h2>{message}</h2>
<button onClick={btnClick}>改变文本</button>
</div>
), document.querySelector('#app')
)
</script>
需要注意的是,jsx使用多个标签时,最外层只能有一个标签。
我们可以看到按钮已经显示了,也绑定了点击事件,可是点击按钮页面没变化。我们可以打印点击按钮后message的值,此时message已经变成了hello react。页面没有发生变化,是因为数据变化了,我们没有重新调用ReactDOM.render函数。
我们可以将ReactDOM.render函数封装到一个函数中,点击按钮的时候调用这个函数,使得页面重新渲染。
<script type="text/babel">
let message = 'hello world'
function btnClick() {
message = 'hello react'
console.log(message);
render()
}
function render() {
ReactDOM.render(
(
<div>
<h2>{message}</h2>
<button onClick={btnClick}>改变文本</button>
</div>
), document.querySelector('#app')
)
}
render()
</script>
此时点击按钮我们可以看到hello world变成了hello react。
在上面,我们提到ReactDOM.render接收的第一个参数可以是html元素,也可以是组件。那么接下来我们将代码封装到一个组件中。
我们使用类的方式封装组件。定义一个类继承自React.Component。定义的类中实现一个render函数,并且在render函数中返回jsx内容,之后react会帮助我们渲染内容。
<script type="text/babel">
class App extends React.Component {
render() {
return (
<div>
<h2>hello world</h2>
<button>改变文本</button>
</div>
)
}
}
ReactDOM.render(<App/>, document.querySelector('#app'))
</script>
通过以上代码,我们在页面中看到文本和按钮。
我们把数据定义在当前对象的state中。当数据发生变化时,我们可以调用this.setState来更新数据,并且通知react进行update操作。react在进行update操作时,就会重新调用render函数,并且使用最新数据来渲染界面。
我们在调用btnClick方法时,会发现this指向的是undefined。此时我们需要通过bind方法来绑定当前对象的this。
<script type="text/babel">
class App extends React.Component {
constructor() {
super()
// this.message = 'hello world'
this.state = {
message: 'hello world'
}
}
render() {
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={this.btnClick.bind(this)}>改变文本</button>
</div>
)
}
btnClick() {
// this.message = 'hello react'
// this.state.message = 'hello react'
// console.log(this);
// console.log(this.state);
this.setState({
message: 'hello react'
})
}
}
ReactDOM.render(<App/>, document.querySelector('#app'))
</script>