React系列之 React入门

原文地点:https://gmiam.com/post/react-…

React 是一个 JS 库,主假如经由历程支配数据的体式格局去支配 DOM,为何要重造轮子呢,因为 FB 觉的如今市面上的 MV* 框架关于建立大型运用顺序不够直观,不能满足需求,所以诞生了 React。

React 如今官方的引见是 Declarative、Component-Based、Learn Once, Write Anywhere,实在最先推出时重要的特征是 Virtual DOM,因为 DOM 支配老是很慢的,而 JS 的机能日益向上,所以 React 内部用 JS 保护一颗 DOM 树,每次数据变了从新天生一颗树与之前的做对照,把现实变化的处所运用到实在的 DOM 上。实在说它机能高,只不过是用 JS 的体式格局盘算出最小的 DOM 支配,所以机能就上来了。

说到这里我们现实支配下吧,这里假定你熟习 node、babel、webpack 体式格局,固然你也能够挑选你喜欢的体式格局 传送门

起首建立目次构造

react-demo

    .babelrc

    index.html

    src
        app.js

index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>React App</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="bundle.js"></script>
  </body>
</html>

app.js

var React = require( 'react' )
var ReactDOM = require( 'react-dom' )

var HelloMessage = React.createClass( {
    render: function () {
        return <div>Hello {this.props.name}</div>
    }
})

ReactDOM.render( <HelloMessage name="John" />, document.getElementById( 'app' ) )

.babelrc

{ "presets": ["es2015","react"] }

装置依靠 npm install --save react react-dom babel-preset-react babel-loader babel-core

编译监听 webpack src/app.js bundle.js -w --module-bind 'js=babel'

翻开 index.html 检察结果

先说下 jsx 语法,React 让你不须要再写 html 拼接字符等支配,而是直接写 html,js 处置惩罚放到 { } 里誊写,官方供应 jsx 语法非必要,也能够离开写纯 js 的,如上面的经由编译后

"use strict";

var HelloMessage = React.createClass({
  displayName: "HelloMessage",

  render: function render() {
    return React.createElement(
      "div",
      null,
      "Hello ",
      this.props.name
    );
  }
});

ReactDOM.render(React.createElement(HelloMessage, { name: "John" }), document.getElementById( 'app' ));

然则能够看出这么贫苦没人去手写的

再来说下组件,React 的观点就是给运用分层,建立一个个组件,末了拼出一个页面,组件轻易后期的保护、扩大、以及再重用,随着组件的越多背面写的代码越少,来个例子

var Avatar = React.createClass({
  render: function() {
    return (
      <div>
        <PagePic pagename={this.props.pagename} />
        <PageLink pagename={this.props.pagename} />
      </div>
    );
  }
});

var PagePic = React.createClass({
  render: function() {
    return (
      <img src={'https://graph.facebook.com/' + this.props.pagename + '/picture'} />
    );
  }
});

var PageLink = React.createClass({
  render: function() {
    return (
      <a href={'https://www.facebook.com/' + this.props.pagename}>
        {this.props.pagename}
      </a>
    );
  }
});

ReactDOM.render(
  <Avatar pagename="Engineering" />,
  document.getElementById('app')
);

能够看到组件要供应本身的 render 要领,组件能够互相嵌套,数据经由历程 this.props 单向通报

同时须要注重

属性 class 要写成 className,for 写成 htmlFor,因为它们是 js 的保留字

关于render 返回的内容只能有一个顶级标签,假如标签凌驾多行要用 ( ) 包括

关于 props 不要去转变它,会致使一些不可预知的题目,别的官方引荐用 es6 的 … 支配符去挂载属性

var props = { foo: 'default', bar:'bar' };
var component = <Component {...props} foo={'override'} />;
console.log(component.props.bar); // 'bar'
console.log(component.props.foo); // 'override'

这里有个特别属性 this.props.children,来个例子

var NotesList = React.createClass({
  propTypes: {
        children: React.PropTypes.array.isRequired,
  },
  render: function() {
    return (
      <ol>
      {
        React.Children.map(this.props.children, function (child) {
          return <li>{child}</li>;
        })
      }
      </ol>
    );
  }
});

ReactDOM.render(
  <NotesList>
    <span>hello</span>
    <span>world</span>
  </NotesList>, document.getElementById('app')
);

同时能够看到这里供应了 propTypes 能够给属性做搜检,考证申明 children 必需供应且是一个数组(多个),更多的范例考证能够 看这里

前面建立组件都是经由历程 React.createClass ,能够经由历程 es6 class 语法

class HelloMessage extends React.Component {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}
ReactDOM.render(<HelloMessage name="Sebastian" />, document.getElementById('app'));

另有 Stateless Functions 体式格局

function HelloMessage(props) {
  return <div>Hello {props.name}</div>;
}
ReactDOM.render(<HelloMessage name="Sebastian" />, document.getElementById('app'));

官方引荐只管写 stateless functions ,因为将来会优化这些来防止无用的搜检和内存分派

下面看下怎样写事宜

var Input = React.createClass({
  getInitialState: function() {
    return {value: 'Hello!'};
  },
  handleChange: function(event) {
    this.setState({value: event.target.value});
  },
  render: function () {
    var value = this.state.value;
    return (
      <div>
        <input type="text" value={value} onChange={this.handleChange} />
        <p>{value}</p>
      </div>
    );
  }
});

ReactDOM.render(<Input/>, document.getElementById('app'));

骆驼式的 on 语法即可监听事宜,事宜是规范的跨浏览器的事宜,虽然内联写法,然则是托付完成的~

说到了事宜交互能够就要设及猎取实在的 dom 节点,React 经由历程 ref 设置,来个例子

var React = require( 'react' )
var ReactDOM = require( 'react-dom' )

var MyComponent = React.createClass({
  handleClick: function() {
    this.refs['myinput'].focus()
  },
  render: function() {
    return (
      <div>
        <input type="text" ref="myinput" />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.handleClick}
        />
      </div>
    );
  }
});

ReactDOM.render(
  <MyComponent />,
  document.getElementById('app')
);

ref 字符属性的体式格局将来会被烧毁,官方引荐运用 ref callback 体式格局

var MyComponent = React.createClass({
  handleClick: function() {
    if (this.myTextInput !== null) {
      this.myTextInput.focus();
    }
  },
  render: function() {
    return (
      <div>
        <input type="text" ref={(ref) => this.myTextInput = ref} />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.handleClick}
        />
      </div>
    );
  }
});

ReactDOM.render(
  <MyComponent />,
  document.getElementById('app')
);

说到这里看下组件的生命周期与怎样更新,照样来个例子

var Timer = React.createClass({
  getInitialState: function() {
    return {secondsElapsed: 0};
  },
  tick: function() {
    this.setState({secondsElapsed: this.state.secondsElapsed + 1});
  },
  componentDidMount: function() {
    this.interval = setInterval(this.tick, 1000);
  },
  componentWillUnmount: function() {
    clearInterval(this.interval);
  },
  render: function() {
    return (
      <div>Seconds Elapsed: {this.state.secondsElapsed}</div>
    );
  }
});

ReactDOM.render(<Timer />,  document.getElementById('app'));

生命周期有三个重要部份

  • Mounting 插进去 dom

    • getInitialState()

    • componentWillMount()

    • componentDidMount ()

  • Updating 从新衬着

    • componentWillReceiveProps(object nextProps)

    • shouldComponentUpdate(object nextProps, object nextState)

    • componentWillUpdate(object nextProps, object nextState)

    • componentDidUpdate(object prevProps, object prevState)

  • Unmounting 移除 dom

    • componentWillUnmount()

周期供应了 will 要领在事变发作之前挪用, did 要领在事变法神以后挪用,详细检察这里

关于更新,上面的例子在组件 componentDidMount (插进去 dom 后) hook 中定时更新组件的 state,state变更会致使 render 从新衬着页面

关于这里说下机能题目,虽然假造dom盘算历程很快,然则许多时刻我们能够防止它的盘算以更好的优化处置惩罚

比方 一个组件的更新能够会致使它的子组件一同随着更新,子组件极能够没有变化,但同样会举行一次diff运算,白白浪费了时候,所以 React 供应了 shouldComponentUpdate 钩子函数,默许是直接返回 true,也及是每次都运算比较,所以我们能够在这里优化,来个例子

React.createClass({
  propTypes: {
    value: React.PropTypes.string.isRequired
  },
  shouldComponentUpdate: function(nextProps, nextState) {
      return this.props.value !== nextProps.value;
  },
  render: function() {
    return <div>{this.props.value}</div>;
  }
});

这里只要 value 变化的时刻在从新衬着盘算,不然直接跳过

关于上面的浅对照,React 供应了通用解决方案 PureRenderMixin 扩大,运用 React 的 mixins 功用即可自动完成处置惩罚比对

var PureRenderMixin = require('react-addons-pure-render-mixin');
React.createClass({
  mixins: [PureRenderMixin],

  render: function() {
     return <div>{this.props.value}</div>;
  }
});

然则假如有深层构造,上面的处置惩罚能够不会按预期事情,比方

//  this.props.value 的值为 { foo: 'bar' }
// nextProps.value 的值为 { foo: 'bar' },
// 然则对象的援用差别,致使不会相称
this.props.value !== nextProps.value; // true

而且假如我们不小心治理援用的话也会激发另一些题目,比方这个组件有一个父组件

React.createClass({
  getInitialState: function() {
    return { value: { foo: 'bar' } };
  },

  onClick: function() {
    var value = this.state.value;
    value.foo += 'bar'; // ANTI-PATTERN!
    this.setState({ value: value });
  },

  render: function() {
    return (
      <div>
        <InnerComponent value={this.state.value} />
        <a onClick={this.onClick}>Click me</a>
      </div>
    );
  }
});

起首内部组件获得 { foo: 'bar' },点击后动身 value 更新 { foo: 'barbar' },触发 re-rendering 顺序,内部组件将会获得 { foo: 'barbar' },然则 this.props.value 与 nextProps.value 指向同一个援用,致使任何时刻比对都是 true,而致使页面不更新

而且假如父组件运用 PureRenderMixin 的话,因为修改雷同援用所以也会致使父组件的 re-rendering 不触发

那末了该怎样处置惩罚呢?请看下一篇 Immutable-js 来拯救你~

    原文作者:我没有的文采
    原文地址: https://segmentfault.com/a/1190000006930718
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞