React 快速上手 - 04 基础特性 JSX、Props、State、Lifecycle、Event、Style
目标
掌握 react 的基础特性
- 语法 JSX
- 属性 Props
- 状态 State
- 生命周期 Lifecycle
- 事件 Event
- 样式 Style
基础特性
react.js 本身只是一个精简的类库,提供了几个特性或者说是工具,每个话题深入都可以长篇大论。
我这里只关注使用,毕竟轮子造出来还是用的,而不是观赏。
1. JSX 语法
我的理解 jsx 就是 html + 表达式 的混合体
1.1 请用 ( ... ) 把 jsx 代码包含起来
const Element1 = () => (<h2>组件1 - 常量</h2>)
这样写的理由
- 低版本的兼容性
- 多行书写不会报错
当然新版里如果你单行可以省略
1.2 必须有个顶级标签
错误
let Element4 = () => {
return (
<h2>组件4 - es6 箭头函数</h2>
<h2>组件4 - es6 箭头函数</h2>
)
}
正确
let Element4 = () => {
return (
<div>
<h2>组件4 - es6 箭头函数</h2>
<h2>组件4 - es6 箭头函数</h2>
</div>
)
}
如果你只有一个标签,自己本身就是顶级标签,无需加
1.3 { ... } 开始你的js表达式
function ElementShow(props) {
return (
<div>
<p>字符串: {props.name} </p>
<p>日期变量: {props.date.toLocaleTimeString()}</p>
</div>
)
}
分别打印 属性值、时间函数
1.4 对于没有子元素的标签来说,请关闭标签
<div>
<ElementProps />
</div>
结束符 /
codepen
2. 属性 Props
2.1 属性值 都是只读的
function ElementShow(props) {
props.isShow = true // 只读不能修改
...
打印截图
2.2 特殊的几个 属性值
记忆就行,和我们之前写 html 有些差异
我看着都是因为 js 中保留字关系
| jsx | html |
|---|---|
| tabIndex | index |
| className | class |
| htmlFor | for |
示例
const ElementProps = () => (
<div tabIndex="0" className="divbg" >
JSX 属性 tabIndex、className
</div>
)
2.3 默认使用驼峰格式 camelCase
错误
<Foo
UserName="hello"
phone_number={12345678}
/>
正确
<Foo
userName="hello"
phoneNumber={12345678}
/>
2.4 如果属性值为 true, 可以直接省略
错误
<Foo
hidden={true}
/>
正确
<Foo
hidden
/>
2.5 key 属性是怎么回事
示例
<ul>
{NavRoutes.map((route, index) => (
<li key={route.id}>
{route.title}
</li>
))}
</ul>
如果不写呢
看来是绕不过的
总结
react利用key来识别组件,它是一种身份标识标识
同层的唯一就行,不用全局唯一
避免使用数组的index作为key值
2.6 防注入攻击
代码
const jsContent = `
<script type="text/javascript">
alert("JSX 防注入攻击!")
</script>`
const ElementInject = () => <div>{jsContent}</div>
打印
内容在渲染之前都被转换成了字符串,这样可以有效地防止 XSS(跨站脚本) 攻击
2.7 childen 表示子节点对象
这个属性表示,当前组件嵌套的对象集合
render() {
return(
<RadioGroup>
<RadioButton value="first">First</RadioButton>
<RadioButton value="second">Second</RadioButton>
<RadioButton value="third">Third</RadioButton>
</RadioGroup>
)
}
RadioGroup的props.childen就是这三个RadioButton
你可能会问这有什么用,我们可以用来加工呀,各种循环、克隆、修改,当然我是不太推荐这样去修改 dom 对象
codepen
3. 状态 State
组件内部的数据管理对象,自动状态控制
有的同学可能对 MVVM 比较了解,一定会说 React 怎么没有双向绑定
这可能就是设计思想问题了,不想给工具赋予过多负重,轻巧才灵活,下一章,我会通过一个函数解决双向绑定来处理表单操作,就几行代码
这里我们还是谈谈基础操作,懂得同学可以 PASS
3.1 初始化
class ElementStateStatic extends Component {
constructor(props) {
super(props)
this.state = {date: new Date()}
}
render() {
return <p>初始时间 => {this.state.date.toLocaleString()}</p>
}
}
constructor是组件构造函数,给this.state初始值时 要用key/val形式的对象jsx中使用时直接this.state.data对象调用即可
3.2 更新
class ElementStateUpdate extends Component {
constructor(props) {
super(props)
this.date = props.date
this.state = {date: new Date()}
}
componentDidMount() {
if (this.date !== undefined) {
// 传值方式
this.setState({date: this.date})
// 函数方式
// this.setState((state, props) => {
// return {date: this.date}
// })
}
}
render() {
return <p>更新时间 => {this.state.date.toLocaleString()}</p>
}
}
需要使用 this.setState 函数设置
简单操作,直接 传入 key / value 的对象
- 如果需要之前的
state或者组件属性props,需要写成
this.setState((state, props) => {
let date = state.data
date = date.addDay(10)
return {date}
})
codepen
4. 生命周期 Lifecycle
4.1 组件有三种状态
| 状态 | 说明 |
|---|---|
| Mount | 已插入真实 DOM |
| Update | 正在被重新渲染 |
| Unmount | 已移出真实 DOM |
4.2 组件周期函数
| 状态 | 说明 |
|---|---|
| componentWillMount | 在渲染前调用,在客户端也在服务端。 |
| componentDidMount | 在第一次渲染后调用,只在客户端。 |
| componentWillReceiveProps | 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。 |
| shouldComponentUpdate | 返回一个布尔值。在组件接收到新的props或者state时被调用。 |
| componentWillUpdate | 在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。 |
| componentDidUpdate | 在组件完成更新后立即调用。在初始化时不会被调用。 |
| componentWillUnmount | 在组件从 DOM 中移除的时候立刻被调用。 |
4.3 示例打印周期过程
代码
class ElementLifecycle extends Component {
constructor(props) {
super(props)
this.date = props.date
this.state = {date: this.date}
}
componentWillMount() {
console.log('componentWillMount 在渲染前调用')
}
componentDidMount() {
console.log('componentDidMount 在第一次渲染后调用')
if (this.date !== undefined) {
this.setState({date: this.date})
}
}
componentWillReceiveProps(nextProps) {
console.log(
'componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用',
nextProps
)
}
shouldComponentUpdate(nextProps, nextState) {
console.log(
'shouldComponentUpdate 在组件接收到新的props或者state时被调用',
nextProps,
nextState
)
return true // 返回一个布尔值,大家可以试着在这里返回 false
}
componentWillUpdate(nextProps, nextState) {
console.log(
'componentWillUpdate 在组件接收到新的props或者state但还没有render时被调用',
nextProps,
nextState
)
}
componentDidUpdate(prevProps, prevState) {
console.log(
'componentDidUpdate 在组件完成更新后立即调用',
prevProps,
prevState
)
}
componentWillUnmount() {
console.log('componentWillUnmount 在组件从 DOM 中移除的时候立刻被调用')
}
render() {
return <p>时间 => {this.state.date.toLocaleString()}</p>
}
}
打印截图
codepen
5. 事件 Event
在 react 里使用事件,写法很多,这里采用官方推荐的方式
5.1 无参数传递
- 采用非箭头函数定义事件
handleChange(e) {
...
}
- 在构造函数时绑定事件
class InputView extends Component {
constructor(props) {
...
this.handleChange = this.handleChange.bind(this)
}
使用 bind(this) 方式
- 绑定事件
<input
...
onChange={this.handleChange}
/>
5.2 有参数传递
- 事件参数要放在最后
handleChangeVal(val, e) {
console.log(val)
this.setState({value: e.target.value})
}
- 绑定事件
<input
...
onChange={this.handleChangeVal.bind(this, '123')}
/>
5.3 例子
class InputView extends Component {
constructor(props) {
super(props)
this.state = {value: ''}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(e) {
this.setState({value: e.target.value})
}
handleChangeVal(val, e) {
console.log(val)
this.setState({value: e.target.value})
}
handleSubmit(e) {
e.preventDefault() // 阻止事件
console.log('handleSubmit')
}
render() {
return (
<form onSubmit={this.handleSubmit} style={{display: 'inline-flex'}}>
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
<input
type="text"
value={this.state.value}
onChange={this.handleChangeVal.bind(this, '123')}
/>
<input type="submit" value="提交" />
<p>{this.state.value}</p>
</form>
)
}
}
codepen
6. 样式 Style
有两种方式维护样式
6.1 import 样式文件
-
base.css样式文件
.bg {
background-color: rgb(101, 40, 241);
color: white;
font-weight: 500;
}
-
.js中引入
import './base.css'
6.2 直接编写 style
- 编写
style对象
const styles = {}
styles.fill = {
position: 'relative',
height: '200px',
width: '500px'
}
...
- 传值使用
<div style={styles.fill}>...
- 混合使用
<div
style={{
...styles.fill,
...styles.hsl,
background: `hsl(${params.h}, ${params.s}%, ${params.l}%)`
}}
>
可以发现这样的写法,对编程控制样式还是很有用的