React 快速上手 - 04 基础特性 JSX、Props、State、Lifecycle、Event、Style

前端之家收集整理的这篇文章主要介绍了React 快速上手 - 04 基础特性 JSX、Props、State、Lifecycle、Event、Style前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

目录

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

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

错误
<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>
  )
}
RadioGroupprops.childen 就是这三个 RadioButton

你可能会问这有什么用,我们可以用来加工呀,各种循环、克隆、修改,当然我是不太推荐这样去修改 dom 对象

codepen

https://codepen.io/ducafecat/...

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

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_199_403@4.4.1 计划取消 3 个生命周期函数@H_534_404@

分别是 componentWillMount,componentWillReceiveProps,componentWillUpdate

理由是在新的升级中,存在漏洞(在Facebook上,他们维护了超过50,000个React组件。 )

注意:
弃用警告将在未来的16.x版本中启用,但旧版生命周期将继续运行至17.x版。
即使在17.x版中,仍然可以使用它们,但它们会以『UNSAFE_』为前缀被重命名,以表明它们可能会引起问题。我们还准备了一个自动化的脚本来在现有代码中对它们重新命名。
UNSAFE_componentWillMount() UNSAFE_componentWillReceiveProps() UNSAFE_componentWillUpdate()
@H_199_403@4.4.2 新增 getDerivedStateFromProps @H_534_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,返回 null

@H_199_403@4.4.3 新增 getSnapshotBeforeUpdate + componentDidUpdate @H_534_404@
getSnapshotBeforeUpdate() 在最新的渲染输出提交给DOM前将会立即调用。它让你的组件能在当前的值可能要改变前获得它们。这一生命周期返回的任何值将会 作为参数被传递给 componentDidUpdate()
// 代码
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,比如改改 宽 高 位置

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

https://codepen.io/ducafecat/...

6. 样式 Style

有两种方式维护样式

6.1 import 样式文件

.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}%)`
    }}
  >

可以发现这样的写法,对编程控制样式还是很有用的

本文代码

参考


© 会煮咖啡的猫咪
微信 ducafecat
镜像 Git

原文链接:https://www.f2er.com/react/301538.html

猜你在找的React相关文章