React ES6+ 入门指引

codepen 上的代码请 fork 后再修改。

环境基础

  • Chrome、FireFox等主流浏览器陆续支持 ES6+ 语法。
  • QQ、360、搜狗等浏览器已支持 ES6+ 语法。
  • 微软全面转移到 Edge。
  • 淘宝不再支持 IE 8 。
  • 项目已使用 webpack、babel 等来提供转义支持。

简介

A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES
一个用于搭建用户界面的js库

核心思路:假定按照人机交互活动的不同状态来设计UI,根据状态的迁移来自动渲染页面。同时,react 通过组件化来分治状态。

Hello World

// 引入 js 类库 
import React from 'react' 
import ReactDOM from 'react-dom' 

// 定义 HelloWorld 组件 
class HelloWorld extends React.Component {
  render() {
    // return 中是 JSX 语法
    return (
      <div>
        Hello, world!
      </div>
    );
  }
}

// 找到 HTML 中的 id="root" 的标签,将 Hello 作为子元素插入 
ReactDOM.render(<HelloWorld/>, document.getElementById('root'));

codepen

ReactDOM.render()

在客户端将 react 组件渲染成 HTML 的方法,在一般的 web app 中只在入口 js 文件中写一处。

JSX

一种在 js 中书写 HTML 的简单方式,可以在其中通过 {} 来使用 js 表达式、变量、函数等。需要注意的是,由于 class 是 js 的关键字/保留字,所以 HTML 中的 class 需要写成 className 。简单语法如下。

const generateJSX = (arg) => {
  return <h3>{arg}</h3>
};

class HelloWorld extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      val: {key: 'JSX中使用对象的值'},
      ifelse: '与其写那些匿名函数箭头函数,不如提出来写更好维护。'
    };
  }
  render() {
    return (
      <div>
        <h1>JSX</h1>
        <h3>{this.state.val.key}</h3>
        <h3>{true?'JSX中不能直接使用if-else,可以使用三元表达式':null}</h3>
        {(function() {
          if (true) {
            return <h3>在JSX中使用立即执行的匿名函数来写if-else</h3>
          }
        })()}
        {true && <h3>单if的时候可以用表达式&&jsx的方式来写</h3>}
        {(() => {
          if (true) 
            return <h3>在JSX中使用立即执行的箭头函数来写if-else</h3>
        })()}
        {generateJSX(this.state.ifelse)}
      </div>
    );
  }
}

ReactDOM.render(<HelloWorld/>, document.getElementById('root'));

codepen

需要注意的是,顶层只能有一对标签。

// bad
return 
  <div></div>
  <div></div>

// good
return 
  <div>
    <div></div>
  </div>

为什么要使用 JSX

使用 JSX 时。

<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>

不使用 JSX 时。

React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)

就一般的 web 开发来说,显然第一种比较直观;对于不一般的 web 开发者来说,也还是第一种比较直观。

React 组件(Component)

React 支持自定义组件,而组件化,是工程化的基础之一。React 支持自定义组件和传参(props)。将自定义组件类比 HTML 标签,参数就类似标签属性,能在 HTML 中怎么使用标签,就能在 JSX 中怎么使用组件。

定义组件

一般由两种方式:函数和 es 6 class 。

函数方式:

function genComA(props={}) {
  return <div>hello</div>
}

const genComB = (props={}) => {
  return <div>hello</div>
};

class:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

传参

前面已经有过很多示例。

在 React 中,可以传递给组件的参数类型和 js 一致,包括 number、string、boolean、object、function 等。在组件中通过 this.props 获取接收到的参数。

class HiName extends React.Component {
  render() {
    return <div>Hi, {this.props.name}</div>
  }
}

class HelloWorld extends React.Component {
  render() {
    return (
      <div>
        <HiName name={'sweetie'}/>
      </div>
    );
  }
}

// 输出 hi, sweetie

以函数形式创建的组件,则没有 this ,也就没有 this.props ,是通过封装成对象的形式传递,直接用 js 函数传参的方式获取即可。:必须首字母大写,否则失效。

function Bye(props) {
  return <div>{props.name}, goodbye.</div>
}

class HelloWorld extends React.Component {
  render() {
    return (
      <div>
        <Bye name={'sweetie'}/>
      </div>
    );
  }
}

this.props.children

React 中有个保留的参数,叫 this.props.children ,主要用于封装和动态加载子组件。常见的用法有单页面 web app 中 header 和 footer 固定,内部内容动态变化等。

class App extends Component {
  render() {
    return (
      <div>
        <Header />
        <div>
          {this.props.children}
        </div>
        <Footer />
      </div>
    )
  }
}

参数校验

React 支持参数校验,包括 js 的数据类型、自定义类型、非空、枚举等。

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

Greeting.propTypes = {
  name: React.PropTypes.string
};

具体参考官网

状态(state)

React 组件基于自身的 state 变化来触发 render ,并进行相应的计算,达到渲染的效果。所以 state 的使用,是 React 中最重要的部分。

  • React 组件的生命周期节点为 mount -> (update) -> unmount
  • 其中 mountunmount 在生命周期中只执行一次,update 执行 0 到多次。
  • mountupdate 都会触发 render
  • 对于 mountupdate 都有 willdid 两种处理函数,对于 unmount 只有 componentWillUnmount
  • 提供 shouldComponentUpdate 来处理比较复杂的情况下组件 state 变化是否渲染,以提升性能。紧急逃生,慎用
  • 提供 componentWillReceiveProps 用于组件 mount 之后接收参数再次更新 state 。
class PropsCount extends React.Component {
  componentWillMount() {
    console.log('PropsCount will mount')
  }

  componentDidMount() {
    console.log('PropsCount did mount')
  }

  componentWillUpdate(nextProps, nextState) {
    console.log('PropsCount will update')
  }

  componentDidUpdate(prevProps, provState) {
    console.log('PropsCount did update')
  }
  
  render() {
    console.log('PropsCount render')
    return <div>count update by props: {this.props.count}</div>
  }
}

class StateCount extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: props.count};
  }
  
  componentWillMount() {
    console.log('StateCount will mount')
  }

  componentDidMount() {
    console.log('StateCount did mount')
  }

  componentWillUpdate(nextProps, nextState) {
    console.log('StateCount will update')
  }

  componentDidUpdate(prevProps, provState) {
    console.log('StateCount did update')
  }
  
  componentWillReceiveProps(nextProps) {
    this.setState({count: nextProps.count});
  }
  
  render() {
    console.log('StateCount render')
    return <div>count update by state: {this.state.count}</div>
  }
}

class Init extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: props.count}
  }
  
  componentWillMount() {
    console.log('Init will mount')
  }

  componentDidMount() {
    console.log('Init did mount')
  }

  componentWillUpdate(nextProps, nextState) {
    console.log('Init will update')
  }

  componentDidUpdate(prevProps, provState) {
    console.log('Init did update')
  }
  
  render() {
    console.log('Init render')
    return <div>init: {this.state.count}</div>
  }
}

class HelloWorld extends React.Component {
  addOne = () => {
    this.setState({count: this.state.count + 1});
  };
  
  constructor(props) {
    super(props);
    this.state = {count: 0};
  }

  componentWillMount() {
    console.log('HelloWorld will mount')
  }

  componentDidMount() {
    console.log('HelloWorld did mount')
  }

  componentWillUpdate(nextProps, nextState) {
    console.log('HelloWorld will update')
  }

  componentDidUpdate(prevProps, provState) {
    console.log('HelloWorld did update')
  }
  
  render() {
    console.log('HelloWorld render')
    return (
      <div>
        <Init count={this.state.count} />
        <button value="addOne" onClick={this.addOne}>add</button>
        <PropsCount count={this.state.count} />
        <StateCount count={this.state.count} />
      </div>
    );
  }
}

ReactDOM.render(<HelloWorld/>, document.getElementById('root'));

codepen

注意:在 componentWillMount componentWillUpdate 中不要使用 setState。初始化的异步请求最好放在 componentDidMount 里,其他初始化的同步操作放在 constructor 里。

处理事件和获取值

官网参考

class A extends React.Component {
  constructor (props) {
    super(props)
    this.state={name:null}
  }
  
  onChange = (e) => {
    this.setState({name: e.target.value})
  };
  
  render () {
    return <div>
      <input type="text" onChange={this.onChange} />
      <br />
      {this.state.name && <label>hi, {this.state.name}</label>}
    </div>;
  }
}

codepen

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

推荐阅读更多精彩内容