资讯专栏INFORMATION COLUMN

React系列之 React入门

pf_miles / 267人阅读

摘要:原文地址是一个库,主要是通过操作数据的方式去操纵,为什么要重造轮子呢,因为觉的目前市面上的框架对于创建大型应用程序不够直观,不能满足需求,所以诞生了。其实说它性能高,只不过是用的方式计算出最小的操作,所以性能就上来了。

原文地址: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



  
    
    
    React App
  
  
    

app.js

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

var HelloMessage = React.createClass( {
    render: function () {
        return 
Hello {this.props.name}
} }) ReactDOM.render( , 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 (
      
); } }); var PagePic = React.createClass({ render: function() { return ( ); } }); var PageLink = React.createClass({ render: function() { return ( {this.props.pagename} ); } }); ReactDOM.render( , document.getElementById("app") );

可以看到组件要提供自己的 render 方法,组件可以相互嵌套,数据通过 this.props 单向传递

同时需要注意

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

对于render 返回的内容只能有一个顶级标签,如果标签超过多行要用 ( ) 包含

关于 props 不要去改变它,会导致一些不可预知的问题,另外官方推荐用 es6 的 ... 操作符去挂载属性

var props = { foo: "default", bar:"bar" };
var component = ;
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 (
      
    { React.Children.map(this.props.children, function (child) { return
  1. {child}
  2. ; }) }
); } }); ReactDOM.render( hello world , document.getElementById("app") );

同时可以看到这里提供了 propTypes 可以给属性做检查,验证说明 children 必须提供且是一个数组(多个),更多的类型验证可以 看这里

前面创建组件都是通过 React.createClass ,可以通过 es6 class 语法

class HelloMessage extends React.Component {
  render() {
    return 
Hello {this.props.name}
; } } ReactDOM.render(, document.getElementById("app"));

还有 Stateless Functions 方式

function HelloMessage(props) {
  return 
Hello {props.name}
; } ReactDOM.render(, 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 (
      

{value}

); } }); ReactDOM.render(, 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 (
      
); } }); ReactDOM.render( , document.getElementById("app") );

ref 字符属性的方式未来会被废弃,官方推荐使用 ref callback 方式

var MyComponent = React.createClass({
  handleClick: function() {
    if (this.myTextInput !== null) {
      this.myTextInput.focus();
    }
  },
  render: function() {
    return (
      
this.myTextInput = ref} />
); } }); ReactDOM.render( , 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 (
      
Seconds Elapsed: {this.state.secondsElapsed}
); } }); ReactDOM.render(, 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 
{this.props.value}
; } });

这里只有 value 变化的时候在重新渲染计算,否则直接跳过

对于上面的浅对比,React 提供了通用解决方案 PureRenderMixin 扩展,应用 React 的 mixins 功能即可自动实现处理比对

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

  render: function() {
     return 
{this.props.value}
; } });

但是如果有深层结构,上面的处理可能不会按预期工作,例如

//  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 (
      
    );
  }
});

首先内部组件得到 { foo: "bar" },点击后出发 value 更新 { foo: "barbar" },触发 re-rendering 程序,内部组件将会得到 { foo: "barbar" },但是 this.props.value 与 nextProps.value 指向同一个引用,导致任何时候比对都是 true,而导致页面不更新

而且如果父组件应用 PureRenderMixin 的话,由于改动相同引用所以也会导致父组件的 re-rendering 不触发

那最后该如何处理呢?请看下一篇 Immutable-js 来解救你~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80396.html

相关文章

  • React入门脚手架搭建项目

    摘要:前言写此系列博客的目的是对所学知识点的总结和梳理,包括填坑方案分享,希望能帮助到还并不会使用的开发者入门官方文档中文文档社区项目搭建按照官方提供的搭建项目全局安装或全局安装后可以使用这条命令创建名为的项目启动 前言 写此系列博客的目的是对所学React知识点的总结和梳理,包括填坑方案分享,希望能帮助到还并不会使用React的开发者入门React React官方文档React中文文档R...

    BingqiChen 评论0 收藏0
  • 前端文档收集

    摘要:系列种优化页面加载速度的方法随笔分类中个最重要的技术点常用整理网页性能管理详解离线缓存简介系列编写高性能有趣的原生数组函数数据访问性能优化方案实现的大排序算法一怪对象常用方法函数收集数组的操作面向对象和原型继承中关键词的优雅解释浅谈系列 H5系列 10种优化页面加载速度的方法 随笔分类 - HTML5 HTML5中40个最重要的技术点 常用meta整理 网页性能管理详解 HTML5 ...

    jsbintask 评论0 收藏0
  • 前端文档收集

    摘要:系列种优化页面加载速度的方法随笔分类中个最重要的技术点常用整理网页性能管理详解离线缓存简介系列编写高性能有趣的原生数组函数数据访问性能优化方案实现的大排序算法一怪对象常用方法函数收集数组的操作面向对象和原型继承中关键词的优雅解释浅谈系列 H5系列 10种优化页面加载速度的方法 随笔分类 - HTML5 HTML5中40个最重要的技术点 常用meta整理 网页性能管理详解 HTML5 ...

    muddyway 评论0 收藏0
  • 前端资源系列(4)-前端学习资源分享&前端面试资源汇总

    摘要:特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方,还请斧正... 托管: welcome to git,欢迎交流,感谢star 有好友反应和斧正,会及时更新,平时业务工作时也会不定期更...

    princekin 评论0 收藏0

发表评论

0条评论

pf_miles

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<