react入门与实战(二):JSX及react的生命周期(上)

这篇文章所包含的内容如下,方便检索:
JSX
react如何setState
react进行事件绑定
react的生命周期

正文

react的JSX

什么是JSX

jsx是一种嵌入式的类XML的语法。它可以被转换成合法的JavaScript,其实就是一个JavaScript语法扩展。类似于模板语言,但它具有JavaScript的全部能力。JSX 最终会被编译为 React.createElement()函数调用,返回称为 “React 元素” 的普通 JavaScript 对象。

react 没有强迫大家一定要用JSX,但是我觉得确实用JSX会方便很多很多!直接上代码 ↓

const element = <h1>Hello, world</h1>;
等价于
var element = React.createElement("h1", null, "Hello, world");

// 在JSX中使用变量
let name  = 'world'
const element = <h1>Hello, {name}</h1>;

// 在JSX中使用表达式
function a1() {
  return <h1>Hello, {1 + 1}</h1>
}

// 在花括号{}里面不能使用直接使用if else语句

// 条件判断
function a2(isBol) {
  if (isBol) {
    return <h1>Hello, in..Bol</h1>
  }
  return <h1>Hello, {1 + 1}</h1>
}

function a3(name) {
  return name && <h1>Hello, {name}</h1>
}

function a4(name) {
  return name ? <h1>Hello, {name}</h1> : null
}

// 列表渲染1
function a5(arr) {
  return (arr && arr.length > 0 &&
    arr.map((item, idx) => {
      const key = 'key:' + idx // 这里最好还是使用ID作为可以
      // 在这里可以判断业务逻辑需要渲染啥内容
      return <h1 key={key}>Hello, {item}</h1>
    }))
}
// 列表渲染2
function a6(arr) {
  const listItems = numbers.map((number, idx) =>
    <li key={idx}>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

建议:使用map的时候一定要加上key,让react能够知道是哪些元素做了改变。最好用当前列表的独一无二的字符串来代替,比如ID,不建议用索引index,除非实在没其他数据。vue的v-for也有key,最后的道理都是一样的 即提高diff效率。如果有机会可以单独拿来聊一聊。

react的setState

现在我们需要创建另一个my-app-test02项目(或者直接拿第一天的项目复制一份),然后在其views下创建新文件夹StateDemo,新建StateDemo.js(这里改成jsx也行,看个人喜好以及IDE的支持度)以及StateDemo.scss

npm i -D node-sass sass-loader
我习惯使用scss这个css预处理器,大家也可以看个人喜好,使用比如less或者是Stylus
tips:node-sass太容易安装失败了,所以失败了大家别慌,一般可以切换淘宝镜像源解决,或者你有一个好的木第孑解决,当然大家自行百度吧 一般都有,我这边不详细说,如果真搞不了可以私聊我,这些相信对大家来说都是小问题。

好吧,居然出意外了,提示sass-loader期望的node-sass版本不对,看起来应该是node-sass有更新然后loader那边还是旧的导致,问题不大,让我看下最近的版本更新如何:

npm uninstall -D node-sass 咱先把刚刚装好的删了,因为提示报错,如果你也遇到这样的 别慌,重新安装即可,当然没遇到最好哈

提示node-sass跟sass-loader版本不匹配导致

npm i -D node-sass@4.14.1
这个4.14.1版本从何而来呢,其实是根据npm网上查看他的历史版本找到的

查看npm的node-sass历史版本

现在项目能够正常跑起来了,cra默认支持sassloader,所以大家不必再去配置了。现在的项目结构如下:

 ....
└── src
    ├── ...
    ├── views +
        └── StateDemo+
          ├── StateDemo.scss +
          └── StateDemo.js +
import React from 'react';
import './StateDemo.scss';

class StateDemo extends React.Component {
    state = {
        count: 0
    }
    
    render() {
        return <div className="state-demo-container">
            <button onClick={() => {
                this.setState({
                    count: this.state.count + 1
                })
            }}>click-{this.state.count}</button>
        </div>
    }
}

export default StateDemo;

以上是一个简单的累加小demo,非常简单的逻辑,点击button,计数count加1
你可以能会有以下的问题:
className JSX中为何用className代替class,因为class是关键字
react绑定事件都是在on+大驼峰 比如 onClick onChange
react 事件你要在JSX语法里面传入一个函数作为事件处理,而不是一个字符串
this.setState是什么 为何是this.state.count

先说说为何是setState来更新数据,其实这个真要说肯定要花长篇大论,我们这作为一个简单的入门,可以先理解他是如何是用的,以后有机会或许可以提一下。

setState() 将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。这是用于更新用户界面以响应事件处理器处理服务器数据的主要方式

`setState(updater, [callback])`

updater可以是俩种形式:
一种为带形参的函数
即:`(state, props) => stateChange`

this.setState((state, props) => { // props后面会说,state即定义的state
  return {counter: state.counter + 1};
});

另一种为对象类型
this.setState({count: 2}) 
this.setState({count: 2}, () => {
  // 在这个回调中能拿到全新的quantity
  console.log(this.state.count)
})

你可能会说 为何我不可以直接像vue那样this.用this.state.count = xxx来更新值,如果我们了解setState原理就知道,setState不仅仅只是修改state的值,他更重要的更难是触发React的更新机制进行diff,然后更新到真实的dom里。这里仅仅要求大家先掌握更新state的方法。

vue为何能够直接触发UI更新呢?因为vue在创建UI的时候已经将data数据收集并且进行重写(setter会去触发更新)。

setState看起来是异步的,其实这个跟他的实现原理有关。所以才会有网上很多人说他啥时候是同步啥时候是异步。其他的可以看下别的大佬写的 《你真的了解setState吗?》

react事件的写法

下面我会介绍大家几种常用的写法

1.箭头函数写法

性能差,很简单,但是每次render都会重复创建函数

import React from 'react';
import './StateDemo.scss';
class StateDemo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }

    addCount () {
        this.setState({
            count: this.state.count + 1
        }, () => {
            console.log(this.state.count);
        })
    }

    render() {
        const {count} = this.state
        return <div className="state-demo-container">
            <button onClick={() => this.addCount()}>click-{count}</button>
        </div>
    }
}

2.官网推荐bind写法

官方推荐,但是麻烦

import React from 'react';
import './StateDemo.scss';
class StateDemo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
        this.addCount = this.addCount.bind(this)
    }

    addCount () {
        this.setState({
            count: this.state.count + 1
        }, () => {
            console.log(this.state.count);
        })
    }

    render() {
        const {count} = this.state
        return <div className="state-demo-container">
            <button onClick={this.addCount}>click-{count}</button>
        </div>
    }
}

3.直接事件bind写法

每次render都要bind一次,性能不好,但不太影响

import React from 'react';
import './StateDemo.scss';
class StateDemo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }

    addCount () {
        this.setState({
            count: this.state.count + 1
        }, () => {
            console.log(this.state.count);
        })
    }

    render() {
        const {count} = this.state
        return <div className="state-demo-container">
            <button onClick={this.addCount.bind(this)}>click-{count}</button>
        </div>
    }
}

4.public class fields 语法

新ES6写法,建议用这种

import React from 'react';
import './StateDemo.scss';
class StateDemo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }

    addCount = () => {
        this.setState({
            count: this.state.count + 1
        }, () => {
            console.log(this.state.count);
        })
    }

    render() {
        const {count} = this.state
        return <div className="state-demo-container">
            <button onClick={this.addCount}>click-{count}</button>
        </div>
    }
}

上面介绍了四种常用的绑定事件方法,或许你会说,如果要传参咋办啊,接下来我一一道来。

e表示合成事件,React 根据 W3C 规范来定义这些合成事件,所以你不需要担心跨浏览器的兼容性问题。

事件传参写法↓

// 1、箭头函数
addCount (e, id) {
   console.log(e)
   console.log(id) // 123 
}
<button onClick={(e) => this.addCount(e, 123)}>click-{count}</button>

// 2、官网推荐bind写法
addCount (e) { 
  console.log(e);
  console.log(e.target.getAttribute('data-id'));
}
<button data-id={123} onClick={this.addCount}>click-{count}</button>

// 3、直接事件bind写法
addCount (id, e) { // 合成事件会作为后面一个参数被传入
  console.log(e)
  console.log(id) // 123 
}
<button onClick={this.addCount.bind(this, 123)}>click-{count}</button>

// 4、public class fields 语法
addCount = (e) => {
  console.log(e);
  console.log(e.target.getAttribute('data-a'));
}
<button data-id={123} onClick={this.addCount}>click-{count}</button>

如果要带参的话,箭头函数以及直接bind事件都比较简单

react的生命周期

这里说的是指React.Component的生命周期

生命周期图

常用的生命周期如下

  1. constructor(props)
  2. componentDidMount()
  3. componentDidUpdate(prevProps, prevState, snapshot)
  4. componentWillUnmount()

不常用的生命周期如下

  1. shouldComponentUpdate(nextProps, nextState)
  2. static getDerivedStateFromProps(props, state)
  3. getSnapshotBeforeUpdate(prevProps, prevState)
  4. static getDerivedStateFromError(error)
  5. componentDidCatch(error, info)

具体使用方法咱下次再聊

项目demo我会上传到GitHub,大家有需要可自行download


参考链接:
jsx
react事件处理
react合成事件
npm node-sass
react lifecycle
GitHub-demo

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,322评论 5 465
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,288评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,227评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,015评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,936评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,534评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,995评论 3 389
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,616评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,907评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,923评论 2 315
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,741评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,525评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,016评论 3 301
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,141评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,453评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,054评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,249评论 2 339