目录
React 快速上手 - 04 基础特性 JSX、Props、State、Lifecycle、Event、Style
目标
掌握 react 的基础特性
- 语法 JSX
- 属性 Props
- 状态 State
- 生命周期 Lifecycle
- 事件 Event
- 样式 Style
基础特性
react.js 本身只是一个精简的类库,提供了几个特性或者说是工具,每个话题深入都可以长篇大论。
我这里只关注使用,毕竟轮子造出来还是用的,而不是观赏。
1. JSX 语法
我的理解 jsx 就是 html + 表达式@H_403_60@ 的混合体
1.1 请用 ( ... )@H_403_60@ 把 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 { ... }@H_403_60@ 开始你的js表达式
function ElementShow(props) { return ( <div> <p>字符串: {props.name} </p> <p>日期变量: {props.date.toLocaleTimeString()}</p> </div> ) }
1.4 对于没有子元素的标签来说,请关闭标签
<div> <ElementProps /> </div>
结束符 /@H_403_60@
codepen
https://codepen.io/ducafecat/...
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@H_403_60@
错误 <Foo UserName="hello" phone_number={12345678} /> 正确 <Foo userName="hello" phoneNumber={12345678} />
2.4 如果属性值为 true,可以直接省略
错误 <Foo hidden={true} /> 正确 <Foo hidden />
2.5 key@H_403_60@ 属性是怎么回事
示例
<ul> {NavRoutes.map((route,index) => ( <li key={route.id}> {route.title} </li> ))} </ul>
如果不写呢
看来是绕不过的
总结
react利用key来识别组件,它是一种身份标识标识
同层的唯一就行,不用全局唯一
避免使用数组的index作为key@H_403_60@ 值
2.6 防注入攻击
const jsContent = ` <script type="text/javascript"> alert("JSX 防注入攻击!") </script>` const ElementInject = () => <div>{jsContent}</div>
打印
内容在渲染之前都被转换成了字符串,这样可以有效地防止 XSS(跨站脚本) 攻击
2.7 childen@H_403_60@ 表示子节点对象
这个属性表示,当前组件嵌套的对象集合
render() { return( <RadioGroup> <RadioButton value="first">First</RadioButton> <RadioButton value="second">Second</RadioButton> <RadioButton value="third">Third</RadioButton> </RadioGroup> ) }
RadioGroup@H_403_60@ 的
props.childen@H_403_60@ 就是这三个
RadioButton@H_403_60@
你可能会问这有什么用,我们可以用来加工呀,各种循环、克隆、修改,当然我是不太推荐这样去修改 dom 对象
codepen
https://codepen.io/ducafecat/...
3. 状态 State
组件内部的数据管理对象,自动状态控制
有的同学可能对 MVVM@H_403_60@ 比较了解,一定会说
React@H_403_60@ 怎么没有双向绑定
这可能就是设计思想问题了,不想给工具赋予过多负重,轻巧才灵活,下一章,我会通过一个函数解决双向绑定来处理表单操作,就几行代码
这里我们还是谈谈基础操作,懂得同学可以 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@H_403_60@ 是组件构造函数,给
this.state@H_403_60@ 初始值时 要用
key/val@H_403_60@ 形式的对象
jsx@H_403_60@ 中使用时直接
this.state.data@H_403_60@ 对象调用即可
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@H_403_60@ 函数设置
简单操作,直接 传入 key / value@H_403_60@ 的对象
this.setState((state,props) => { let date = state.data date = date.addDay(10) return {date} })
codepen
https://codepen.io/ducafecat/...
4. 生命周期 Lifecycle
4.1 组件有三种状态
状态 | 说明 |
---|---|
Mount | 已插入真实 DOM |
Update | 正在被重新渲染 |
Unmount | 已移出真实 DOM |
4.2 组件周期函数
状态 | 说明 |
---|---|
componentDidMount | 在第一次渲染后调用,只在客户端。 |
shouldComponentUpdate | 返回一个布尔值。在组件接收到新的props或者state时被调用。 |
componentDidUpdate | 在组件完成更新后立即调用。在初始化时不会被调用。 |
componentWillUnmount | 在组件从 DOM 中移除的时候立刻被调用。 |
getDerivedStateFromProps | 组件实例化后和接受新属性时将会调用 新增 |
getSnapshotBeforeUpdate | 在最新的渲染输出提交给DOM前将会立即调用 新增 |
4.3 示例打印周期过程
class ElementLifecycle extends Component { constructor(props) { super(props) this.date = props.date this.state = {date: this.date} } componentDidMount() { console.log('componentDidMount 在第一次渲染后调用') if (this.date !== undefined) { this.setState({date: this.date}) } } shouldComponentUpdate(nextProps,nextState) { console.log( 'shouldComponentUpdate 在组件接收到新的props或者state时被调用',nextProps,nextState ) return true // 返回一个布尔值,大家可以试着在这里返回 false } componentDidUpdate(prevProps,prevState) { console.log( 'componentDidUpdate 在组件完成更新后立即调用',prevProps,prevState ) } componentWillUnmount() { console.log('componentWillUnmount 在组件从 DOM 中移除的时候立刻被调用') } render() { return <p>时间 => {this.state.date.toLocaleString()}</p> } }
打印截图
codepen
https://codepen.io/ducafecat/...
4.4 react 16.x@H_403_60@ 新版本变动
@H_583_403@4.4.1 计划取消 3 个生命周期函数@H_340_404@
分别是 componentWillMount@H_403_60@,
componentWillReceiveProps@H_403_60@,
componentWillUpdate@H_403_60@
理由是在新的升级中,存在漏洞(在Facebook上,他们维护了超过50,000个React组件。 )
注意:@H_583_403@4.4.2 新增
弃用警告将在未来的16.x版本中启用,但旧版生命周期将继续运行至17.x版。
即使在17.x版中,仍然可以使用它们,但它们会以『UNSAFE_』为前缀被重命名,以表明它们可能会引起问题。我们还准备了一个自动化的脚本来在现有代码中对它们重新命名。
UNSAFE_componentWillMount()@H_403_60@
UNSAFE_componentWillReceiveProps()@H_403_60@
UNSAFE_componentWillUpdate()@H_403_60@
getDerivedStateFromProps@H_403_60@ @H_340_404@
组件实例化后和接受新属性时将会调用
// 组件
class ElementLifecycleNew extends Component {
constructor(props) {
super(props)
this.state = {}
}
static getDerivedStateFromProps(nextProps,prevState) {
console.log(
'getDerivedStateFromProps 组件实例化后和接受新属性时将会调用',prevState
)
// return null // 无需改变 返回 null
return {
date: new Date('2011-11-11 11:11:11')
}
}
render() {
return <p>{this.state.date.toLocaleString()}</p>
}
}
// 调用
<ElementLifecycleNew date={new Date('2009-09-09 09:09:09')} />
如果你不想改变状态 state@H_403_60@,返回 null@H_403_60@
@H_583_403@4.4.3 新增 getSnapshotBeforeUpdate + componentDidUpdate@H_403_60@ @H_340_404@
getSnapshotBeforeUpdate()@H_403_60@ 在最新的渲染输出提交给DOM前将会立即调用。它让你的组件能在当前的值可能要改变前获得它们。这一生命周期返回的任何值将会 作为参数被传递给
componentDidUpdate()@H_403_60@。
// 代码
class ElementLifecycleNew2 extends Component {
listRef = React.createRef()
constructor(props) {
super(props)
this.state = {
date: props.date
}
}
componentDidMount() {
console.log('componentDidMount')
this.setState({date: new Date('2011-11-22 22:22:22')})
}
getSnapshotBeforeUpdate(prevProps,prevState) {
console.log('getSnapshotBeforeUpdate',prevState,this.state)
return {
offset: 80
}
}
componentDidUpdate(prevProps,snapshot) {
console.log('componentDidUpdate',snapshot)
this.listRef.current.style.top = `${snapshot.offset}px`
}
render() {
return (
<div
style={{
height: 200,width: 150,backgroundColor: 'blue',position: 'relative',color: '#fff'
}}
>
<p>{this.state.date.toLocaleString()}</p>
<div
ref={this.listRef}
style={{
height: 20,backgroundColor: 'red',top: 0,position: 'absolute'
}}
/>
</div>
)
}
}
// 调用
这个例子的流程是:
1. `componentDidMount` 中修改了 state 触发 `getSnapshotBeforeUpdate`
2. `getSnapshotBeforeUpdate` 获取修改前的 属性、状态,已修改的 状态,然后一个修改值 `offset`
3. `componentDidUpdate` 中的 `snapshot` 获取修改值 ,直接 `ref` `dom` 修改 `style`
简单说就是不修改 state 更新机制,来维护
dom@H_403_60@,比如改改 宽 高 位置
5. 事件 Event
在 react 里使用事件,写法很多,这里采用官方推荐的方式
5.1 无参数传递
- 采用非箭头函数定义事件
handleChange(e) {
...
}
- 在构造函数时绑定事件
class InputView extends Component {
constructor(props) {
...
this.handleChange = this.handleChange.bind(this)
}
使用
bind(this)@H_403_60@ 方式
- 绑定事件
<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
https://codepen.io/ducafecat/...
6. 样式 Style
有两种方式维护样式
6.1 import@H_403_60@ 样式文件
.bg {
background-color: rgb(101,40,241);
color: white;
font-weight: 500;
}
-
.js@H_403_60@ 中引入
import './base.css'
6.2 直接编写 style@H_403_60@
- 编写
style@H_403_60@ 对象
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}%)`
}}
>
可以发现这样的写法,对编程控制样式还是很有用的
本文代码
参考
- Index as a key is an anti-pattern
- Introducing JSX
- Rendering Elements
- Components and Props
- State and Lifecycle
- Handling Events
- lists-and-keys.html
- React.Component
原文链接:https://www.f2er.com/react/301538.html