什么是JSX
JSX是javascript的扩展语言, 在JSX中, 你不仅可以写 html 还可以 写 javascript 表达式
以下是简单的例子
const myName = '遥近'
const template = <h1>Hello, {myName}</h1>
ReactDOM.render(template, document.getElementById('app'))
可以看到 在 jsx 中, 可以通过 {} 来编写javascript表达式, 这样就可以很方便得渲染你想呈现的内容
jsx是一个表达式
更神奇的是, jsx也是一个表达式, 也就是说你可以将其作为函数返回, 或者赋值到一个变量中.
function createName(name) {
if (name) {
return <h1>Hello, {name}</h1>
} else {
return <h1>Hello, World</h1>
}
}
ReactDOM.render(createName(), document.getElementById('app'))
jsx中设置属性
在jsx中,使用驼峰命名来设置属性值, 例如 className 而不是 class , 想在属性中使用表达式, 使用 { } 包裹即可
组件 和 props
在react 中, 组件可以分为函数组件和 class 组件, 组件是由各个元素组合起来, 一般可以用来复用的, 并接受参数, 即props, 最终返回用来展示页面的 react 元素, 不论是函数组件和或者class 组件, ==都必须以大写字母作为开头==, 不然react 将视为普通的dom元素
函数组件
一旦你使用了大写作为开头, 那么react将视为组件, 你在标签中定义的属性将会作为参数(props)给到组件内部使用, 子元素标签将会作为props 的 children 属性 给到组件内部
// 定义一个Welcome函数组件
function Welcome(props) {
console.log(props)
return (
<div>
<div>你好, {props.name}</div> // 你好遥近
<div>{props.children}</div> {/* <span>您好啊我是子元素</span> */}
</div>
)
}
const element = (
<Welcome name="遥近">
<span>您好啊我是子元素</span>
</Welcome>
)
ReactDOM.render(element, document.getElementById('app'))
class组件
class 组件是 使用了es6 的 class 继承 React.Component 来定义的组件, 通过这个方式定义的组件, 可以拥有react的生命周期, state 等其他特征
props
在组件中,我们接受props, 但是, 需要注意的是, 无论如何我们都不可以改变props的值, ==props只是只读的==
State
props不能更改, 为了随数据的更改,页面保持 变化, react 引入了一种新的概念, 称为 state, 想定义state, 就不能使用函数组件, 必须通过class组件定义
export default class Time extends React.Component {
constructor(props) {
super(props) // 调用了super才可以使用this,添加state, 并且在this中读取props
this.state = { date: new Date() }
}
}
通过class定义组件后,我们还需要在constructor中定义并且初始state, 需要注意的是, 必须先调用super, 才可以读取this, 这是es6 class 定义的规则, 因为子类是没有自己的this的, 只能继承父类的this, 在对这个this加以使用
现在让我们在 componentDidMount 创建定时器, 以及在 componentWillUnmount 清除定时器, 最后通过render 方法读取state的值, 就可以看到数据和页面是同步更新的了
// 挂载完毕执行
componentDidMount() {
this.timerID = setInterval(() => this.tick(), 1000)
}
// 卸载时候执行
componentWillUnmount() {
clearInterval(this.timerID)
}
tick() {
this.setState({
date: new Date(),
})
}
render() {
return (
<div>
<h1>你好</h1>
<p>现在时间是: {this.state.date.toLocaleTimeString()}</p>
</div>
)
}
需要注意的state 只能通过 this.setState 来进行更新, 并且State 的更新可能是异步的, state是单项数据流的, 意味着不可以通过子组件去改变父组件的state
定义事件
在html中,我们定义事件, 例如onclick, 使用小字母, 但是在react中, 你需要使用驼峰命名来定义事件
<div>
<button onClick={this.handleClick}>点击测试</button>
</div>
在事件中
如果你需要阻止默认行为, 你必须显式得使用 .preventDefault()
想要在事件中,使用组件的实例(即可以读取this) 你需要通过以下几种方法
constructor绑定this
constructor(props) {
super(props)
// 通过在constructor中改变this执行
this.handleClick = this.handleClick.bind(this)
}
render() {
return (
<div>
<button onClick={this.handleClick}>点击测试</button>
</div>
)
}
public class fields 语法 public class fields 语法
handleClick = () => {
console.log('this is:', this);
}
其他方法
<button onClick={(e) => this.handleClick(e)}>点击测试</button>
<button onClick={this.handleClick.bind(this)}>点击测试</button>
需要读取event对象,使用箭头函数, 需要显式地传递
==官方推荐使用前面两种方法定义事件, 因为使用箭头函数可能会造成不必要的渲染, 这是因为当你将箭头函数作为props传递给子组件的时候, 回调函数每次在render都会创建一个新的函数, 导致不必要的渲染==
状态提升
当某些数据多个子组件需要共同使用的时候, 可以将数据放到父组件统一进行处理,React称为状态提升
组合
在react中, 想跟vue在使用插槽, react称为组合, 可以很方便实现
import React from 'react'
class Combination extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
<div>{this.props.title}</div>
<div>{this.props.left}</div>
{this.props.children}
</div>
)
}
}
function SlotPage () {
return (
<Combination title='这是组合组件, 也就是vue的插槽类似' left={<Left />}>
<div>哈哈哈,我是子元素</div>
</Combination>
)
}
function Left () {
return (
<div>我是左插槽</div>
)
}
export default SlotPage
你可以理解成, 在React中, props是可以接受来自 class 和 React 元素作为 对象传到别的 组件中, 用于使用