React 入门实例教程

http://www.ruanyifeng.com/blog/2015/03/react.html

分类

 

React 入门实例教程

作者: 阮一峰

日期: 2015年3月31日

现在最热门的前端框架,毫无疑问是 React 。

上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑。

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。

由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。

这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App 解决方案。衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机(参见《也许,DOM 不是答案》)。

既然 React 这么热门,看上去充满希望,当然应该好好学一下。从技术角度,可以满足好奇心,提高技术水平;从职业角度,有利于求职和晋升,有利于参与潜力大的项目。但是,好的 React 教程却不容易找到,这一方面因为这项技术太新,刚刚开始走红,大家都没有经验,还在摸索之中;另一方面因为 React 本身还在不断变动,API 一直在调整,至今没发布1.0版。

我学习 React 时,就很苦恼。有的教程讨论一些细节问题,对入门没帮助;有的教程写得不错,但比较短,无助于看清全貌。我断断续续学了几个月,看过二十几篇教程,在这个过程中,将对自己有帮助的 Demo 都收集下来,做成了一个库 React Demos 。

下面,我就根据这个库,写一篇全面又易懂的 React 入门教程。你只需要跟着每一个 Demo 做一遍,就能初步掌握 React 。当然,前提是你必须拥有基本 JavaScript 和 DOM 知识,但是你读完就会发现,React 所要求的预备知识真的很少。

零、安装

React 的安装包,可以到官网下载。不过,React Demos 已经自带 React 源码,不用另外安装,只需把这个库拷贝到你的硬盘就行了。


$ git clone .com:ruanyf/react-demos.git

如果你没安装 git, 那就直接下载 zip 压缩包

下面要讲解的12个例子在各个 Demo 子目录,每个目录都有一个 index.html 文件,在浏览器打开这个文件(大多数情况下双击即可),就能立刻看到效果。

需要说明的是,React 可以在浏览器运行,也可以在服务器运行,但是本教程只涉及浏览器。一方面是为了尽量保持简单,另一方面 React 的语法是一致的,服务器的用法与浏览器差别不大。Demo13 是服务器首屏渲染的例子,有兴趣的朋友可以自己去看源码。

一、HTML 模板

使用 React 的网页源码,结构大致如下。


<!DOCTYPE html>
<html>
  <head>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/babel">
      // ** Our code goes here! **
    </script>
  </body>
</html>

上面代码有两个地方需要注意。首先,最后一个 <script> 标签的 type 属性为 text/babel 。这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel" 。

其次,上面代码一共用了三个库: react.js 、react-dom.js 和 Browser.js ,它们必须首先加载。其中,react.js 是 React 的核心库,react-dom.js 是提供与 DOM 相关的功能,Browser.js 的作用是将 JSX 语法转为 JavaScript 语法,这一步很消耗时间,实际上线的时候,应该将它放到服务器完成。


$ babel src --out-dir build

上面命令可以将 src 子目录的 js 文件进行语法转换,转码后的文件全部放在 build 子目录。

二、ReactDOM.render()

ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。


ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('example')
);

上面代码将一个 h1 标题,插入 example 节点(查看 demo01),运行结果如下。

三、JSX 语法

上一节的代码, HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写(查看 Demo02 )。


var names = ['Alice', 'Emily', 'Kate'];

ReactDOM.render(
  <div>
  {
    names.map(function (name) {
      return <div>Hello, {name}!</div>
    })
  }
  </div>,
  document.getElementById('example')
);

上面代码体现了 JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。上面代码的运行结果如下。

JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员(查看 demo03 )。


var arr = [
  <h1>Hello world!</h1>,
  <h2>React is awesome</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('example')
);

上面代码的arr变量是一个数组,结果 JSX 会把它的所有成员,添加到模板,运行结果如下。

四、组件

React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类(查看 demo04)。


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

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

上面代码中,变量 HelloMessage 就是一个组件类。模板插入 <HelloMessage /> 时,会自动生成 HelloMessage 的一个实例(下文的"组件"都指组件类的实例)。所有组件类都必须有自己的 render 方法,用于输出组件。

注意,组件类的第一个字母必须大写,否则会报错,比如HelloMessage不能写成helloMessage。另外,组件类只能包含一个顶层标签,否则也会报错。


var HelloMessage = React.createClass({
  render: function() {
    return <h1>
      Hello {this.props.name}
    </h1><p>
      some text
    </p>;
  }
});

上面代码会报错,因为HelloMessage组件包含了两个顶层标签:h1p

组件的用法与原生的 HTML 标签完全一致,可以任意加入属性,比如 <HelloMessage name="John"> ,就是 HelloMessage 组件加入一个 name 属性,值为 John。组件的属性可以在组件类的 this.props 对象上获取,比如 name 属性就可以通过 this.props.name 读取。上面代码的运行结果如下。

添加组件属性,有一个地方需要注意,就是 class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。

五、this.props.children

this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点(查看 demo05)。


var NotesList = React.createClass({
  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.body
);

上面代码的 NoteList 组件有两个 span 子节点,它们都可以通过 this.props.children 读取,运行结果如下。

这里需要注意, this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。

React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。更多的 React.Children 的方法,请参考官方文档

六、PropTypes

组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。

组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求(查看 demo06)。


var MyTitle = React.createClass({
  propTypes: {
    title: React.PropTypes.string.isRequired,
  },

  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});

上面的Mytitle组件有一个title属性。PropTypes 告诉 React,这个 title 属性是必须的,而且它的值必须是字符串。现在,我们设置 title 属性的值是一个数值。


var data = 123;

ReactDOM.render(
  <MyTitle title={data} />,
  document.body
);

这样一来,title属性就通不过验证了。控制台会显示一行错误信息。


Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.

更多的PropTypes设置,可以查看官方文档

此外,getDefaultProps 方法可以用来设置组件属性的默认值。


var MyTitle = React.createClass({
  getDefaultProps : function () {
    return {
      title : 'Hello World'
    };
  },

  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});

ReactDOM.render(
  <MyTitle />,
  document.body
);

上面代码会输出"Hello World"。

七、获取真实的DOM节点

组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。

但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性(查看 demo07 )。


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

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

上面代码中,组件 MyComponent 的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。

需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click 事件的回调函数,确保了只有等到真实 DOM 发生 Click 事件之后,才会读取 this.refs.[refName] 属性。

React 组件支持很多事件,除了 Click 事件以外,还有 KeyDown 、CopyScroll 等,完整的事件清单请查看官方文档

八、this.state

组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI (查看 demo08 )。


var LikeButton = React.createClass({
  getInitialState: function() {
    return {liked: false};
  },
  handleClick: function(event) {
    this.setState({liked: !this.state.liked});
  },
  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('example')
);

上面代码是一个 LikeButton 组件,它的 getInitialState 方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取。当用户点击组件,导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。

由于 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。

九、表单

用户在表单填入的内容,属于用户跟组件的互动,所以不能用 this.props 读取(查看 demo9 )。


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.body);

上面代码中,文本输入框的值,不能用 this.props.value 读取,而要定义一个 onChange 事件的回调函数,通过 event.target.value 读取用户输入的值。textarea 元素、select元素、radio元素都属于这种情况,更多介绍请参考官方文档

十、组件的生命周期

组件的生命周期分成三个状态:

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实 DOM

React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数。

  • componentWillMount()
  • componentDidMount()
  • componentWillUpdate(object nextProps, object nextState)
  • componentDidUpdate(object prevProps, object prevState)
  • componentWillUnmount()

此外,React 还提供两种特殊状态的处理函数。

  • componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
  • shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用

这些方法的详细说明,可以参考官方文档。下面是一个例子(查看 demo10 )。


var Hello = React.createClass({
  getInitialState: function () {
    return {
      opacity: 1.0
    };
  },

  componentDidMount: function () {
    this.timer = setInterval(function () {
      var opacity = this.state.opacity;
      opacity -= .05;
      if (opacity < 0.1) {
        opacity = 1.0;
      }
      this.setState({
        opacity: opacity
      });
    }.bind(this), 100);
  },

  render: function () {
    return (
      <div style={{opacity: this.state.opacity}}>
        Hello {this.props.name}
      </div>
    );
  }
});

ReactDOM.render(
  <Hello name="world"/>,
  document.body
);

上面代码在hello组件加载以后,通过 componentDidMount 方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。

另外,组件的style属性的设置方式也值得注意,不能写成


style="opacity:{this.state.opacity};"

而要写成


style={{opacity: this.state.opacity}}

这是因为 React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。

十一、Ajax

组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI (查看 demo11 )。


var UserGist = React.createClass({
  getInitialState: function() {
    return {
      username: '',
      lastGistUrl: ''
    };
  },

  componentDidMount: function() {
    $.get(this.props.source, function(result) {
      var lastGist = result[0];
      if (this.isMounted()) {
        this.setState({
          username: lastGist.owner.login,
          lastGistUrl: lastGist.html_url
        });
      }
    }.bind(this));
  },

  render: function() {
    return (
      <div>
        {this.state.username}'s last gist is
        <a href={this.state.lastGistUrl}>here</a>.
      </div>
    );
  }
});

ReactDOM.render(
  <UserGist source="https://api.github.com/users/octocat/gists" />,
  document.body
);

上面代码使用 jQuery 完成 Ajax 请求,这是为了便于说明。React 本身没有任何依赖,完全可以不用jQuery,而使用其他库。

我们甚至可以把一个Promise对象传入组件,请看Demo12


ReactDOM.render(
  <RepoList
    promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')}
  />,
  document.body
);

上面代码从Github的API抓取数据,然后将Promise对象作为属性,传给RepoList组件。

如果Promise对象正在抓取数据(pending状态),组件显示"正在加载";如果Promise对象报错(rejected状态),组件显示报错信息;如果Promise对象抓取数据成功(fulfilled状态),组件显示获取的数据。


var RepoList = React.createClass({
  getInitialState: function() {
    return { loading: true, error: null, data: null};
  },

  componentDidMount() {
    this.props.promise.then(
      value => this.setState({loading: false, data: value}),
      error => this.setState({loading: false, error: error}));
  },

  render: function() {
    if (this.state.loading) {
      return <span>Loading...</span>;
    }
    else if (this.state.error !== null) {
      return <span>Error: {this.state.error.message}</span>;
    }
    else {
      var repos = this.state.data.items;
      var repoList = repos.map(function (repo) {
        return (
          <li>
            <a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br/> {repo.description}
          </li>
        );
      });
      return (
        <main>
          <h1>Most Popular JavaScript Projects in Github</h1>
          <ol>{repoList}</ol>
        </main>
      );
    }
  }
});

十二、参考链接

  1. React's official site
  2. React's official examples
  3. React (Virtual) DOM Terminology, by Sebastian Markbåge
  4. The React Quick Start Guide, by Jack Callister
  5. Learning React.js: Getting Started and Concepts, by Ken Wheeler
  6. Getting started with React, by Ryan Clark
  7. React JS Tutorial and Guide to the Gotchas, by Justin Deal
  8. React Primer, by Binary Muse
  9. jQuery versus React.js thinking, by zigomir

(完)

珠峰培训

简寻

留言(250条)

实在是不能更赞,我能去您的公司打工不。哈哈。
马上仔细跟进。
在中国做一个前端,真的是挺有福气。

相信阮一峰老师~ 先留言后看w 前端新人一只 来这学了很多东西 
React自己也折腾了好几个月~ 挺好玩~ 
thx~

前排支持, 希望能看到你更多的文章.

阮老师的最近的每篇文章,内容都是当下最热门的话题,并且适合初学者阅读。 好厉害!

之前从未接触过React,看了这篇博文之后就有了大概的印象了,提供的示例通俗易懂,非常感谢!

学习了!!!

留个链接, 我是 React 中文社区维护者之一(跟 Facebook 无关..).
社区交流的渠道可以在 http://nav.react-china.org/ 查看.
如果大家有兴趣追最新的消息, 交流跟分享 React, 可以细看一下.

Unmounting:已移出真实 DOM, 是移除吧, 吹毛求疵一下...

真是一篇很好的入门教程!

最近正用React写项目,老阮关于“状态机”的论述也很有帮助

謝謝好文,但是我想指出你文中說 React Native 想要「同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机」是不正確的。

歷史上所有標榜 "Write once, run everywhere" 的項目都失敗了。 React Native 在發表時,說的是 "Learn once, write everywhere"。瀏覽器、 iOS 及 Android 的後端 js 邏輯可以共用,UI 還是得寫三次,但架構版型的思考模式會一樣 (都用 CSS flexbox),畫面元件還是得從 換成 。

一峰大师 的文章果然赞!!!react入门必读文章哈!

引用曲双如的发言:

实在是不能更赞,我能去您的公司打工不。哈哈。
马上仔细跟进。
在中国做一个前端,真的是挺有福气。

他在支付宝

不能更赞啊,谢谢阮老师

老师的文章总是那么深入浅出而又博大精深。daomubiji.org

加油~

基于React的Reagent很赞。

凡是使用 JSX 的地方,都要加上 type="text/jsx" 现在的 react 版本不需要了

Donate 没了?

引用busyStone的发言:

凡是使用 JSX 的地方,都要加上 type="text/jsx"现在的 react 版本不需要了

那是转换成 原生 js 后, 才不用添加的吧.

相信看了您的文章,就很容易入门了吧.果断买本《如何变得有思想》支持一下.

哈哈,一峰老师名气可真大啊。。

一峰老师超赞,布道大师

阮兄能否在结合flux一起讲一下react。

React 可能是个很 NB 的东西,可是看起来很复杂,我没有什么好感。当然,我对它没有好感并不影响它是个 NB、伟大的东西。

看了二十几篇教程就写出个这。。?

阮兄,
请问 React 适合开发什么类型的项目?
如果我的项目围绕在电子商务,酒店订购,餐厅(包括开发管理界面),
React 和 nagularjs 哪一个更适合我呢?
思想差异,优缺点能否说一说 ? 

由于 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。

props,在这里很常见的用法是传参,显然形参你改了也灭用
而state这个属性就要好好把玩了,也说了,交互中很常见的状态

新技术介绍,不错。

学习了,感觉特别棒。

真的很不错,希望阮大侠继续React在中国的布道。

能否解释下 第十个Demo中的isMounted方法的作用和意义?谢谢。

期待阮老师在出一个Reflux的教程

阮老师的博客内容总是这么棒~~

试了一下,四组件类的名称必须是大写字母开头!!!

写的真好,已经入门

引用luobotang的发言:

React 可能是个很 NB 的东西,可是看起来很复杂,我没有什么好感。当然,我对它没有好感并不影响它是个 NB、伟大的东西。

React已经是尽量专注于表现层了,没有加入太多东西,怎么会很复杂。

引用Mrluobo的发言:

能否解释下 第十个Demo中的isMounted方法的作用和意义?谢谢。

只有组件还处于挂载状态下,才有setState从而更新视图的意义。

就是 class 属性需要写成 className 
新版的不需要了 直接写成class 就可以了

写的真好。
这React看起来不是那么简单,语法都搞不清了。改变好大。另外,这东西能debug吗?

写的很通俗易懂

通俗易懂,大赞

Facebook 在 React.js Conf 2015 大会上推出了基于 JavaScript 的开源框架 React Native,结合了 Web 应用和 Native 应用的优势,可以使用 JavaScript 来开发 iOS 和 Android 原生应用。

下面是对 React Native 官方文档的完整中文翻译教程:http://wiki.jikexueyuan.com/project/react-native/

引用haohao的发言:

试了一下,四组件类的名称必须是大写字母开头!!!

我也发现了

看起来怎么又把模板揉进JS里了?

我有点儿贪心了:React能否开发游戏/移动端游戏?

React.findDOMNode 这个调用报错:React is undefined. 这是怎么回事啊?大神

勘误:
只有当子节点多余1个时
多于

谢谢老师

一个错别字:
只有当子节点多余1个时

多于

打算先把这些demo过一遍

非常感谢您分享这篇文章,由衷地感谢!

现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白; 
如果是移动端直接就原生写吧, 实际上也没多少代码量.

引用刘大的发言:

看了二十几篇教程就写出个这。。?

那你还想咋地?

请问两个独立组件之间有什么好的交互方式

感谢博主!现学现用,很有参考价值

第九个例子最好clearInterval一下

引用初学者的发言:

现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白; 
如果是移动端直接就原生写吧, 实际上也没多少代码量.

那你最好去当个教师。不要做前端了

貌似this可以随便用都无视函数作用域?

不错,简单易懂

写的很好,读的很有收获

$ git clone git@github.com:ruanyf/react-demos.git

应该是:

https://github.com/ruanyf/react-demos.git

这样不需要SSH的也可以直接clone

学习了!希望出现flux、reflux、redux教程!

文章开头讲到参见《也许,DOM 不是答案》,和React没太大关系。《也许,DOM 不是答案》是篇值得深思的文章,那篇文章给出的答案是新的页面渲染方式,倾向仍然是web端。
而React只是稍微新一点的编写方式。Native解决的是减少工作量,统一的代码,性能能好吗?已经有太多项目做过这样的尝试了,还说什么“如果能够实现,整个互联网行业都会被颠覆”,别逗了。
React不会解决那篇文章说的问题,也挨不上关系。

您好:我想问您这个框架可以开发网页版组态软件么?可以和requriejs配合么?

Pretty cool!

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

React.render(
<HelloMessage name="John" />,
document.getElementById('example')
);
阮老师,为什么插入之后的html结构,会分别有两个span标签包裹着Hello和{this.props.name}呢?

这段代码是demo4里面的

赞!条理清晰,比较全面而简单,谢谢阮老师!

虽然跟着demo都敲了一下,但是发现自己什么都没有学会,render是干嘛的不知道,还有就是除了这些方法还有哪些方法,也不清楚,是不是我学的太浅了?

老师,能否写个flux入门?

我想知道如何外部引入jsx

申明了type="text/jsx" 引入就会失败

不申明就会有语法错误!

引用初学者的发言:

现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白; 
如果是移动端直接就原生写吧, 实际上也没多少代码量.

所以充其量你永远只是一个小码农。不愿接受新事物,墨守陈规。

看過一些資料, 感覺一直模模糊糊,
看了一下您的教學, 馬上釐清觀念! 感謝老師

写得太好了,太好了

引用曲双如的发言:

实在是不能更赞,我能去您的公司打工不。哈哈。
马上仔细跟进。
在中国做一个前端,真的是挺有福气。

阮老师 好像是在淘宝 少年加油吧

文中说只要调用 setState 方法,就会自己调用 render 方法,重新渲染组件,
八、表单 这节中,我看到 p 标签中使用 {value},input 标签中也是使用value={value},
但是改变 input 中内容,只有 p 中内容跟着改变了,input 的 value 属性值没有跟着改变,
那 render 方法到底是怎么执行的呢?没有重新渲染 input 吗?

您好,我安装了git,用webstorm去push你的代码,总是失败

阮老师自学能力太强了

引用rolin的发言:

貌似this可以随便用都无视函数作用域?

注意看代码下面的bind(this),这是通过function的bind方法指定了作用域,相关链接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

写得真好,学习中

创建组件的变量 首字母要用大写才有用 不知道大家是不是这样

写的很好,有的看官方没看懂,看你的整明白了,支持一下

引用whws的发言:

文中说只要调用 setState 方法,就会自己调用 render 方法,重新渲染组件,
八、表单 这节中,我看到 p 标签中使用 {value},input 标签中也是使用value={value},
但是改变 input 中内容,只有 p 中内容跟着改变了,input 的 value 属性值没有跟着改变,
那 render 方法到底是怎么执行的呢?没有重新渲染 input 吗?

render 的时候重新生成了 Virtual DOM,但重新渲染UI时,React 只会对 Virtual DOM 中发生改变了的部分进行重新渲染。render 后 Virtual DOM 中 input 的 value 属性值其实发生了变化,但和真实 DOM 中 input 的 .value 想用,故没有渲染到UI中。
PS. 你可以通过在 input 上加上 ref="myTextInput",并在 handleChange 里加入 console.log(this.refs["myTextInput"].props); 来打印 Virtual DOM 的属性值来发现其中奥妙。

引用前端菜鸟的发言:

虽然跟着demo都敲了一下,但是发现自己什么都没有学会,render是干嘛的不知道,还有就是除了这些方法还有哪些方法,也不清楚,是不是我学的太浅了?

我建议把每一个3分钟就能看完的例子,用30分钟进行各种改写试验,就能够深入一些。

引用Zoe的发言:

阮老师,为什么插入之后的html结构,会分别有两个span标签包裹着Hello和{this.props.name}呢?

你应该也发现了,他们都有各自的 reactid,是React为了实现以后的查找元素和局部重新渲染。
第八个例子中你可以发现这个事实,选中前面的You或后面Click to toggle中某些字母,此时触发点击事件造成 like 部分的改变,没有使你选中区域的背景和焦点丢失,就是只重绘了中间的那个 span。

引用busyStone的发言:

凡是使用 JSX 的地方,都要加上 type="text/jsx"现在的 react 版本不需要了

目前0.13 版本还是要加的JSXTransformer.js 的,除非转化为原生js

想要看视频教程的同学可以到这里看
http://piliyu.com

如果我想在react组件里嵌入一个jquery的datepicker组件应该怎么来做?

感谢老师的分享

browser.min.js 是用来干嘛的 我看到有的教程里面用的是 JSXTransformer.js 这两者有什么区别吗?

引用兴杰的发言:

阮兄,
请问 React 适合开发什么类型的项目?
如果我的项目围绕在电子商务,酒店订购,餐厅(包括开发管理界面),
React 和 nagularjs 哪一个更适合我呢?
思想差异,优缺点能否说一说 ?


angular适合快速搭建应用,组建比较全,依赖入驻思想,经常写java服务的同学可能很试用,但其根本没有脱离dom结构,是渲染dom结构展现,尤其双向数据绑定在复杂数据交互时候,性能不高;react比较轻,自己重写的虚拟dom渲染比较独特,但组件不全,很多需要自己扩展,写核心的应用或者酷炫效果应该不错,具体看你实际应用吧

你好,我最近在学习react的时候 ,看的是facebook.github.io/react/docs/tutorial.html 的例子,发现怎么好像提交数据时候的url 和 请求数据的url 一样的,这个是怎么回事,似乎和我们常见web 有点不太一样,还望指导一下,谢谢

"Demo11 是服务器首屏渲染的例子"这里说的应该是Demo12吧!

看你Demo11中说ajax请求的数据要通过setState来触发渲染,事实上ajax请求之前就会调用初始的state默认渲染一次,例子中初始state比较简单:
getInitialState: function() {
return {
username: '',
lastGistUrl: ''
};
}
那问题是我请求的数据结构很复杂,那初始state必须得完全照搬复杂的数据结构?要不然第一次渲染时就会报错!

引用初学者的发言:

现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白; 
如果是移动端直接就原生写吧, 实际上也没多少代码量.

你说的这段话很符合你的用户名

阮老师,JSX能在浏览器控制台断点吗?我试了好像不行?是我方法错了吗?

又重新看了一遍,主要是最近react-native推出了android的版本;所以react很值得深入学习理解;最终的方向还是在react-native方向;我看最近很多比如www.reactjs.cn,http://www.webdoes.com/blog/archives/725,都专门讲解了react-native,也很不错,值得学习一下;感谢阮老师。

10分钟入门React系列

一个是get请求,一个是post请求


引用funye的发言:

你好,我最近在学习react的时候 ,看的是facebook.github.io/react/docs/tutorial.html 的例子,发现怎么好像提交数据时候的url 和 请求数据的url 一样的,这个是怎么回事,似乎和我们常见web 有点不太一样,还望指导一下,谢谢

牛逼,这demo都有2000+的star了

大神,git不了啊,老说没权限。。。

引用和风的发言:

大神,git不了啊,老说没权限。。。

直接用浏览器访问这个页面,然后Download ZIP
https://github.com/ruanyf/react-demos

阮老师第一个例程里面的<script type="text/babel"> 貌似写错了 
<script type="text/jsx">
// ** Our code goes here! **
</script>

script type="text/babel" 写成了 script type="text/jsx"

@星光:

谢谢指出,已经更正了。

引用haohao的发言:

试了一下,四组件类的名称必须是大写字母开头!!!

啊,多谢,我就在这地方遇到坑了。阮老师可以考虑补充进去哈:)

我个人的感觉,JSX是需要React解析的,这种语法糖也会改变开发JavaScript的开发方式,时间久了会导致原生JavaScript不熟了,因为好多问题你要前端非常熟悉JavaScript,否则就导致漫天大海的在网上找解决方案。

我个人觉得,类似React的这种东东不要改变JavaScript写代码方式,可以在用JavaScript编写面向对象的组件上解决组件开发中单点的处理,而不是弄一套体系改变前端开发人员的开发方式。

ruanyifeng大大, 
PropTypes 熟悉这一部分是不是有问题哈 .

可以拿最新的 0.14.0 测试一下哦 .

引用初学者的发言:

现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白; 
如果是移动端直接就原生写吧, 实际上也没多少代码量.

- - 那 Facebook 为啥要用 , 不是你想的那样的 .

没有 MVC 框架 , 你写 bootstrap semantic UI 试试

引用rolin的发言:

貌似this可以随便用都无视函数作用域?

函数结尾有个.bind(this),这个this就是传入当前作用域。

还不支持windows 555555555

能有比较完善的demo吗?

有没有什么优秀的开发工具来支持react?

引用星光的发言:

阮老师第一个例程里面的<script type="text/babel"> 貌似写错了
<script type="text/jsx">
// ** Our code goes here! **
</script>

不太明白,应该是"text/jsx"还是"text/babel"

引用题叶的发言:

留个链接, 我是 React 中文社区维护者之一(跟 Facebook 无关..).
社区交流的渠道可以在 http://nav.react-china.org/ 查看.
如果大家有兴趣追最新的消息, 交流跟分享 React, 可以细看一下.

Diff算法解释是否已收入React中文社区http://www.laolifactory.com/index.php/2015/10/19/reacts-diff-algorithm-chinese/

引用Leo的发言:

那是转换成 原生 js 后, 才不用添加的吧.

现在貌似改成了0.14版本后 "text/jsx"改成"text/babel" ,官方不再发布 JSXTransformer.js 了 改成babel解析...
http://www.tuicool.com/articles/NFvYfeB

Demo2 控制台报错
Each child in an array or iterator should have a unique “key” prop

解决办法只要在循环的每个子项添加一个key就行了,代码如下:


var names = ['Alice', 'Emily', 'Kate'];

ReactDOM.render(

{
names.map(function (name, key) {
return Hello, {name}!
})
}
,
document.getElementById('example')
);

http://f00sun.com/

这些东西,花一天时间看一遍官方文档就都知道了好吧。。还看了几个月。。。

为啥这里可以直接写 onClick={this.handleClick} ? 而不是this.handleClick.bind(this)

在DOM4中,HelloMessage是自定义的吗,还是react中有规定,另外如果是自定义的话那首字母必须大写吗,因为我试了下,如果首字母小写的话是不报错,但是也没显示出来,所以这里的名字是自定义,但是首字母必须大写的对吗老师

阮大哥好用心,react 0.14 才出来一个月,这个教程已经更新了,用上了 ReactDOM

四:添加组件属性,有一个地方需要注意,就是 class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。

试了一下,属性class和for都可以在页面上输出,代码(html忘记转义了,再发一次):
var HelloMessage = React.createClass({
render: function() {
return <div>
<p>HelloMessage组件属性</p>
<p>name: {this.props.name}</p>
<p>date: {this.props.date}</p>
<p>class: {this.props.class}</p>
<p>className: {this.props.className}</p>
<p>for: {this.props.for}</p>
<p>htmlFor: {this.props.htmlFor}</p>
</div>;
}
});
ReactDOM.render(
<HelloMessage name="张三" date="2015-10-30" class="icon iocn_home" for="AAA" className="BBB" htmlFor="CCC"/>,
document.getElementById('example')
);

阮老师,能不能把react结合ES6谈一谈呢,与ES5还是有点区别的。

引用pv的发言:

不好意思,没有深入理解学习四:添加组件属性
确实是 class 属性需要写成 className ,for 属性需要写成 htmlFor


谢谢阮老师~

demo2和demo3里迭代数组会报警告: Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using

另外demo9也会报警告不要直接插入document.body.

几个月也太久了吧
我希望1个月能投入生产的

引用ZJZHOME的发言:

谢谢阮老师~

demo2和demo3里迭代数组会报警告: Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using

另外demo9也会报警告不要直接插入document.body.

你可以参考这篇文章:虚拟DOM Diff算法解析

看了阮老师这篇文章收益匪浅!我是做客户端的,之前琢磨react native,看到jsx有点头疼,读完此篇,疑惑全解了。既然也在支付宝,也是同事了,同事中的老师!赞!

非常感谢,文章对我很有帮助,公司最近做react项目,正愁学起来麻烦,这篇绝对是超好的入门教程

良心文章啊。 随react版本变化而更新文章。

ES6版在这,https://github.com/zhuangtongfa/react-demos
求star

引用初学者的发言:

现在真心不想用框架了, knockout, backbone, angular以及这个.
每次为了适应一个新框架, 需要学习很多额外的语法, 而且等到其他人来维护的时候, 却完全维护不动...
我决定以后顶多用个jQuery, 差不多大家都能看明白; 
如果是移动端直接就原生写吧, 实际上也没多少代码量.

先攒一下阮一峰老师,Angularjs现在正在用,完成俩一下项目,感觉很顺,代码量少backbone和angular我认为不能比,angular的模板载入绝了,还有路由都不错感觉比react完整,适合面向对象抽像不强人用,解耦等都不错,阮一峰老师这个文章入门真好,个人认为react面向对象抽像要强才能写的好

现在的框架每一个框架都需要你学习一种语法,这个代价也大..公司换人也困难..无论它多优秀..这个成本也挺高的.

应该是react入门里面最好理解的教程了,最近找了一大圈react教程基本都是复制黏贴好坑人的,这篇绝对秒杀同类型教程

请问,您的例子如何在webstorm里面写呢,因为是html格式的,它一直报错,在js里可以正常提示jsx,如何在写html的时候还让它认识react呢?

想请教一下大神 这里面的中文乱码怎么解决?

React非常优秀,阮老师也一直非常优秀,非常好的一篇入门文章,阮老师一直出精华。
React亮点是html作为了js组件,实现了dom diff和状态机的思想。
React解决的一些问题,其实用一些简易优秀库,各取其核心,一样可以实现需求,而且开发成本也低,不会像React一样,各种查api,时间大部分都花在了看api上
但个人认为,前端开发应该简而大方,不应该被一个react或angular局限在它们的生态圈中。一年前还有很多人在追逐angular,想着统一天下,现在又开始追逐react
没有完美的框架存在。简单了,维护性才好


真心赞一个,给了我们新手不少帮助,

另外在重复一个问题,我也遇到了demo2和demo3里迭代数组会报警告: Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using

这个该怎么解决?

阮老师太牛逼了,所有文章都简洁易懂,学了好多知识。

我都不好意思在潜下去了。。写的好!

引用吖木的发言:

五、this.props.children

function(child){
return {child}
}


这里应该是这样吧?

五、this.props.children

function(child){
return <li>{child}</li>
}

文章很棒,但预测React只叫好不叫座,不建议多看,还是应该多看ES和JQ。再牛B的框架,也绕不开浏览器的渲染机制。至于React还出了Native版的,这个纯属FB的痴心妄想了,Native的一统世界了,让安卓和iOS喝西北风去吗?

demo5应该return <li>{child}</li>;

原来阮老师这篇文章更新了啊,赞!

很好的入门教程~~~希望能有一篇文章,说说reactjs的实现原理~

阮老师,第五点 return {child}; 应该 return <li>{child}</li>

谢谢指出 Demo05已经改过来了。

引用rolin的发言:

貌似this可以随便用都无视函数作用域?

this用在react内部的函数里面,比如render,由react调用肯定没问题,

this用在自定义函数里面,都要有显示绑定this,比如 onChange={this.handleChange}

引用邬畏畏的发言:

我个人的感觉,JSX是需要React解析的,这种语法糖也会改变开发JavaScript的开发方式,时间久了会导致原生JavaScript不熟了,因为好多问题你要前端非常熟悉JavaScript,否则就导致漫天大海的在网上找解决方案。

我个人觉得,类似React的这种东东不要改变JavaScript写代码方式,可以在用JavaScript编写面向对象的组件上解决组件开发中单点的处理,而不是弄一套体系改变前端开发人员的开发方式。

React是可以不用JSX的,可以直接写js

jsx:Hello {this.props.name} 
js:React.createElement("div", null, "Hello ", this.props.name);

主要是jsx的类html语法比起原生js容易构建用户界面,嵌套层次一多自然会去用jsx了,只是做一层预编译


Demo,做得不错

demo 9里面 handleChange 需要传递event进去,还有就是input里面value={this.state.value}

踩到了一个坑。

组件的命名:应该是首字母大写的。

习惯了驼峰命名法的coder,看到这个文章可能会果断小写,题主可否修改下?以免大家误解造成浪费时间,无法继续学习。

ps. 问了一圈得到答案后,搜索了下本页,居然很多人都发现了 - -

感谢分享时下最热的前端开发框架中文版介绍。

一直有关注阮老师的博客,可以说这个博客真正促成了我进入前端行业,感谢!

说回这篇文章,React.js 的几个核心概念都阐明得很清楚,提一点意见,只解释概念和给一些小Demo 是不够的,React.js 的使用情景是数据随时变化、模型之间互有依赖的复杂应用,其革命之处乃是在于数据单向流动的Flux 模型,初学者理解这个模型比弄清组件、传参这些概念重要得多。

组件之间是如何通信的???

当有一组按钮,
点击其中一个添加 active 样式,
其兄弟按钮,删除active样式。
这样的操作,不利用jquery或zepto这样的框架。
在react 中怎样实现呢?

您好,我在执行demo2/inde.html时,报错如下Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using <div>. See https://fb.me/react-warning-keys for more information.
虽然对页面显示没有影响,但是我想知道为何会报这样的错误,以及如何解决?
我有试着百度结果,但是最终还是没有解决,希望您能够抽空解答一下,谢谢……

关于browser 官方放了cdn 速度很不错

<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>

男神,能不能在多写react在实际应用的文章。或者 微博发篇0.13和0.14的区别?因为现在许多教程都是0.13的 而0.14有许变化引用就不同text/jsx也变了 我想知道为什么?

发布这么久了,才看到

看到混写js和html那就给跪了。整一个增强版的前台jsp语言。
膜拜!!

深入一点说的话,Virtual DOM中的Style要写成Object的形式是因为它的DOM-Diff算法的需要,界定add/remove操作

引用李黎的发言:

您好,我在执行demo2/inde.html时,报错如下Warning: Each child in an array or iterator should have a unique "key" prop. Check the top-level render call using <div>. See https://fb.me/react-warning-keys for more information.
虽然对页面显示没有影响,但是我想知道为何会报这样的错误,以及如何解决?
我有试着百度结果,但是最终还是没有解决,希望您能够抽空解答一下,谢谢……

由于React注重UI效率,使用Virtual DOM Diff来提高效率,最小化Html DOM渲染开销,所以遇到DOM nodelist时期望每个node有个key来做引用标识, 这仅仅是一个Warning,一般不会对你的App功能造成影响,但是应该注意此类问题,大规模View中可能会引发性能问题。

解决此问题的方法就是给你的Virtual DOM Nodelist中每个Node加唯一的key标识。

{List.map(function(item){ return (<li key={"Item-"+item.id}>{item.name}</li>); })}

看见React的代码我都感觉好恶心。
没有我写的html页面简洁明了。

引用Nixus的发言:

我有点儿贪心了:React能否开发游戏/移动端游戏?

2D交互游戏肯定是可以的

支持OOP否?比如可以写一个子类,覆盖超类的方法。
有(或将来会有)代码提示IDE插件否?

引用郑晋的发言:


React已经是尽量专注于表现层了,没有加入太多东西,怎么会很复杂。

已经在工作中使用了,React 上手的话还是可以的,但是真的用来做较为复杂的页面,还是要花些时间查看文档的,不是很简单。
而且,完善的功能实现的话,不会只有 React,我做的时候是参照 Flux 的架构,由于不熟悉,真的是有些费劲(这个数据流还真是不寻常....)。

通览一遍,一句话“jQuery把前端带到了极简主义,React把前端带到了复杂主义”。这些DEMO里隐隐看到的都是PHP模板渲染的东西。对,facebook就是用PHP的。把PHP做的事情换成用JS来做,还写得那么复杂,真不明白有什么意义。

引用郑晋的发言:

只有组件还处于挂载状态下,才有setState从而更新视图的意义。

说通俗点,就是当组件渲染完成之后才设置组件的形态(以免get返回数据快过组件渲染速度,造成无法设置组件形态。)

因为ReactJS的大名一直如雷贯耳,所以便花了些时间了解一下。原本以为只是简单的不同于JQuery的封装,但实际上却是完全打破了以前HTML开发的模式。
看到上面一大串的拍马评论,和对那位名为“初学者”的留言用户的抨击,忍不住写下看法。
从使用HTML属性到HTML和CSS分离,再到JavaScript处理逻辑,用了不短的时间。现在很少看到杂糅着各种语言的页面代码。
所以,最初看到ReactJs代码的时候,简直不敢相信眼睛,这么多年分离的结果,又活生生地杂糅到了一起。
歪果仁的创新能力的确强,前端这点东西折腾出了很多新的花样。但是FB的东西,实在是不敢说都是能改变世界的东西。FB为了让PHP更快用HHVM,脱离标准PHP。是的,他们的确是可以做到,很牛逼。但是这样真的好吗?最新的PHP7已经面世,打脸一般地证明了标准PHP同样可以很快。
ReactJS混合了JS代码和HTML代码,其实它只想做一件事情,那就是组件化前端。但是组件化前端真的有必要用这么极端和不优雅的实现方式么?JS的地位如今已经被哄抬到了一个它设计之初都没想到的位置。以至于为了坐上王位,JS必须用它不算坚固的权杖,支撑起自己。JS的语法结构根本很难以这样无限制的拓展和包容一切。
ReactJS概念的确是新颖,但是这不代表它就一定比分离代码和显示的模版优秀。组件化就代表着可复用?组件化就意味着可工程化。分离的模版就没法复用,没法工程化?
最大的一套说辞往往就是“未来的页面会日趋复杂”,真相真的是这样吗?不得不承认,现今的互联网页面的确是比二十年前的页面复杂,但是页面再复杂,也终究是有极限的。简单的设计风格已经逐渐成为设计潮流,复杂的页面难道没有又逐渐变简单的趋势吗?除了淘宝这类电商的页面复杂无比外,还有多少网站是需要极其复杂的动态前端。
越是简单的页面越是能让用户易于理解和提高更好体验不是吗?至于什么丰富的交互,革命性体验,ReactJS和普通前端架构又有什么区别。
组件化可维护性很强,的确,从名称上看起来就有很强维护性。现在后端的代码也是所谓的组件化,甚至各种设计模式的应用,放到现实中的项目,真的能说“可维护性”很强吗?
传统前端所见即所得,我思即我需,应该更为贴近人类思想,这不正是编程语言所一直努力的方向么。
未来前端肯定会有更好的方向和发展,但绝对不会是ReactJS。

@Cheny:

感觉你说的有一定的道理,但是ReactJS能走多远,得用时间去验证和大家的认同

问一句,如果我有一个想重复使用的组件,如果组件定义的代码放在一个单独的js文件里。
多个页面的多个地方要使用这个组件,有什么办法吗?
刚开始学习这个东西,也只是研究性质的,貌似组件的定义和组件的渲染一定要写作一起,不能独立开来的。
//定义
var SingleArticle = React.createClass({
render: function() {
return (

SomeArticle

);
}
});
//渲染
ReactDOM.render(React.createElement(SingleArticle, null), 
document.body);

还有,在式样定义上也觉得蛮奇葩的,JSX不走标准化路线,可能学了之后,没有其他使用的地方。
React Native还是算了吧,开发Native的程序的成本现在也很低了。

文章中对于onClick的处理,没有这样写:this.handleClick.bind(this) 而是直接 this.handleClick()的话,会不会有this在调用时被改变的错误发生?谢谢

你好,我下载的0.14版本中没有了browser.min.js?该怎么将JSX 语法转为 JavaScript 语法?

@奋斗:

browser.min.js是Babel提供的。可以就只用Demo里面的版本。

帅的不能再帅了!!!给您大大的满分!!!

非常浅显易懂,赞
你的blog我一直在看

引用Yuan25的发言:

文章中对于onClick的处理,没有这样写:this.handleClick.bind(this) 而是直接 this.handleClick()的话,会不会有this在调用时被改变的错误发生?谢谢

this.handleClick(); 这里可以这些写,简单说的话是因为这里其实会被解析转换(注意所有的代码写的是jsx,既不是js也不是html,当然最终是会被解析成js),底层还是会调用bind(this)或类似的方式绑定正确的this。

大神您好!本人初学前端;想请教下,demo10的bind(this)的用法,如果我把这个去掉,系统就会报错:
Uncaught TypeError: Cannot read property 'opacity' of undefined
想问下,这里为什么是这样写的呢?
期待回复,谢谢

引用路人甲的发言:

文章很棒,但预测React只叫好不叫座,不建议多看,还是应该多看ES和JQ。再牛B的框架,也绕不开浏览器的渲染机制。至于React还出了Native版的,这个纯属FB的痴心妄想了,Native的一统世界了,让安卓和iOS喝西北风去吗?

你的“预测”在你预测的时间点已经是伪命题。JQ 说的是 jQuery 吗。。。。?这个应该多看?。。。。呵呵呵呵呵呵

this.props.promise.then(
value => this.setState({loading: false, data: value}),
error => this.setState({loading: false, error: error}));

这个没看懂,this.props.promise.then是什么意思?

写的比官方教程清晰多了,可以简单入门,很有帮助,感谢阮老师~

谢谢阮老师

受益匪浅!多谢阮一峰老师!

引用锋的发言:

this.props.promise.then(
value => this.setState({loading: false, data: value}),
error => this.setState({loading: false, error: error}));

这个没看懂,this.props.promise.then是什么意思?

.then()是jquery的方法,参数(success(),error())
=>是es6语法,我理解为
componentDidMount() {
this.props.promise.then(
function(value){this.setState({loading: false, data: value})}.bind(this),
function(error){this.setState({loading: false, error: error})}.bind(this)
)
}

受益匪浅!多谢阮一峰老师!每篇文章都是精华。

阮一峰老师:

var HelloReact = React.createClass({
propTypes:{
title: React.PropTypes.string.isRequired
},
render:function() {
return <h1>{this.props.title}</h1>
}
});
var data = function () {console.log(1);};
var data1 = "ss";
ReactDOM.render(
<HelloReact title={data} />,
document.body
)


这个验证为什么不会报错?

访问react的网页,是不是必须把react.js,react-dom.js,browser.min.js这三个文件下载到客户端才能运行,这几个文件还挺大的,如果真是这样岂不是很影响性能和用户体验?有没有靠谱的解决方法呢

太厉害了,拜读

@Cheny:

同意。
大公司或许可以使劲折腾,小公司还是要多考虑软件的可维护性。
越复杂的东西就越难维护,js+html的模式,对一般开发来说不见得是好事。
或许未来等React更成熟,更优雅,坑填的差不多了,这种模式就流行了。

谢谢教程的帮助,前端学习中,甚至有冲动自己写一个框架。js+html对css提供更好的对接方式,让开发更快。

请问,什么叫“组件类只能包含一个顶层标签”?

学习组件话,先看看 老师的入门一下~

感觉和qt,friemonkey类似,只不过使用的技术更亲近web开发

说实话,目前react是最靠谱的web ui组件化方案了。

1.React的组件化才是web ui部件的正确方向

1.1.组件化集成html ,css,js自我包含一体化,方便复用。

不鼓励使用mvc模式。或者组件内部使用mvc来分离ui与js,但整个page页面是不提倡mvc的。。

1.2.相比angular。Js方便好用

2.React的问题与改进:

2.1. 可视化模板不容易得到dw的支持。。

作为模版,得到类似dw 这类可视化Html ide的支持的是必须的。。

改进建议:使用html文件作为组件,小型组件可以使用ajax读取载入,这样组件可以方便dw的设计。。大型组件可以使用ajax载入,也可以iframe方式载入。。

2.2.组件的html与js的集成是以js为基础的

这导致了界面可视化设计极差。。应该以html dom为基础,在html的基础上内嵌js。。Js本身就是代码,可视化要求相对较低。。Dom 标签使用常用的class 增加一个特点的oocss class来表明一个组件的类型,以及复合组件,或者可增加一个扩展属性。。

2.3.组件的属性以js为主

这带来查看属性值的调试的问题,如果可以在html标签上扩展属性,就方便调试,毕竟浏览器查看工具可以一目了然的查看属性的值

demo13怎么玩的,

请问如果定义 var MyButton = React.createClass({...})放在单独文件里比如 abc.js
html页面引用 <script type="text/babel" src="js/abc.js"></script>

页面来定义在哪里渲染(其实为了重用),页面调用:

<script type="text/babel">
ReactDOM.render(
<div><MyButton text="sure2"/></div>,
document.getElementById('content')
);
</script>

为什么不行?
Uncaught ReferenceError: MyButton is not defined

写的很好.学起来很容易.

比那些什么鬼视频讲的好多了

一目了然, 虽然现在只是大致看了一下 没有一个个demo去尝试着做,
但是的确比其他教程要好得多!

太棒了,清晰明了,受益匪浅

由浅入深,大赞

React个人感觉还是挺简单的。很喜欢阮老师的文章,写的很细致。

学习了,非常感谢!!!

写的非常好,自己琢磨好长时间,没有太懂,来这看了一个晚上,收获很多!非常感谢!

回过头来看,真的不错,

组件化,这个发展的趋势有点像Flex!

感觉前端的发展就是大家在制定一套界面设计的DSL,看谁更经济。

求教啊,在做项目时候,要发布上服务器,broswer.js很大,我用react-tool 把jsx的组件文件转化成了js文件,然后移除了browser.js的引用,页面渲染不出来啊?难道不能缺少browser.js吗?

感觉vue跟react好像

好用,点赞,很好的入门实例,对react有了大概了解,谢谢。

Web的问题是否能够依靠"组件化"来解决是需要讨论的?但现在出现的现象,是我们过于关注技术本身,而忽略了Web自身的特性。如此众多的组件库和框架都试图证明自己是解决Web的不二法则,有注重服务器端解决方案的,例如
* Tag library - Struts Tag
* Template Engineer - Velocity, Freemaker
* Components: Awt/Swing, JSF

有关注客户端的解决方案的,例如
* Flash, Applet
* java-script library: YUI, Dojo
* java-script framework: Angular, EmberJs, Rect.js

那么什么是Web的实质呢?它原本只是用来展现数据的载体,至于什么方式或者方法其实是无所谓,你用Struts Tag也好用Dojo也好,都只是为"展示"这个动作服务的。过分的关注工具的使用,而忽略了技术之外的东西(比如Dom, CSS, javascript语言这些本身的特点)就本末倒置了。

玩玩新东西还是可以的,但个人感觉这种写代码方式会扰乱正常js的写法方式,有的时候学得越多越混,到头来写简单的js都犯低级错误是得不偿失的。

引用郑晋的发言:

只有组件还处于挂载状态下,才有setState从而更新视图的意义。

我还是有疑问,componentDidMount已经是渲染完成了,这就证明组建已经肯定是处于mounting状态的。$.get(url,function)这里的function是成功后的回调,也就是说,数据已经返回了。
1、组件状态是mounting状态。
2、数据已经返回。
为什么还要判断isMounted()?

引用业界大牛的发言:

由于 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。

props,在这里很常见的用法是传参,显然形参你改了也灭用
而state这个属性就要好好把玩了,也说了,交互中很常见的状态

怎么感觉你是 => 张鑫旭大师呢

demo13 npm install 安装后运行node server.js还是报错,应该是jsx编译报错
报错信息是
E:\www\myTest\react-demos-master\demo13\src\server.js:20
<body>
^

SyntaxError: Unexpected token <
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:373:25)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:968:3

烦问这是什么原因?试过直接安装babel-core 和 babel-cli也不行

@spring:

看demo13的README,需要 npm run build。

引用阮一峰的发言:

@spring:

看demo13的README,需要 npm run build。

哇喔,果然,谢谢偶像


我们这项目 要用 React和OnSen UI开发 苦苦找了很多 看的 很痛苦 !
当我看到您分享的 入门很快,谢谢
希望有些深入React 见解 案例 分享下 
谢谢!!!! 



引用郑晋的发言:

只有组件还处于挂载状态下,才有setState从而更新视图的意义。

可是componentDidMount()不就是视图挂载后才响应的事件吗?

歪果仁奇思妙想,果仁跟风。

1、demo10中的,this.timer是表示timer是组件实例的一个属性么?2、setInterval函数中的回调函数,为什么还要加.bind(this)?

引用cristal000o的发言:

1、demo10中的,this.timer是表示timer是组件实例的一个属性么?2、setInterval函数中的回调函数,为什么还要加.bind(this)?

你可以搜索下js的bind用法

引用cristal000o的发言:

1、demo10中的,this.timer是表示timer是组件实例的一个属性么?2、setInterval函数中的回调函数,为什么还要加.bind(this)?

setInterval()内部的this指向window,而我们需要当前的对象,故绑定this传入。

引用cristal000o的发言:

1、demo10中的,this.timer是表示timer是组件实例的一个属性么?2、setInterval函数中的回调函数,为什么还要加.bind(this)?

忘了说,bind()是ES5的方法,所以想兼容浏览器,需要自己写一个bind()函数。

老師,
我練習完你的範例之後,
試著將組件拆成外部一個個的js檔後發現就報error,
我也試著上網查了相關的教學,
發現大家的教學好像都是將組件寫在同一隻js或是html中, 
不知道如果是以下的結構要怎麼樣往外拆?

遠本寫在index.html中的js


var Test = React.createClass({
render: function () {
return (
Test
);
}
});

ReactDOM.render(
,
document.getElementById('main')
);


想要改成link:

刚一打开页面感觉好长一篇,看完才发现下面都是评论。。。

@Cheny:

层住观点我比较赞同,框架这东西仁者见仁智者见智,不是流行的就是好的,适合自己就好

引用郑晋的发言:


React已经是尽量专注于表现层了,没有加入太多东西,怎么会很复杂。

今天再来看的,react生态是最复杂的

最初看到您的文章觉得写的也不错,但是并没有出彩的地方(个人愚见)!直到今日学习react,看了好多教程,包括官方英文的教程,皆不能得其要领!直至看到阮老师的react文章,一句话真是对我醍醐灌顶,帮助甚大,特此鸣谢!!!

引用rolin的发言:

貌似this可以随便用都无视函数作用域?

初代版本有做 this 作用域的封装~

组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求, 这里应该是propType,应该是小写开头的。

@Cheny:

严重赞同!真不觉得“初学者”说的有错,代码维护连续性,确实存在这些问题。不能从正面解决问题出发,除了打击、抨击,显得高高在上,很爽?!

您好,我在使用最新的react开发的过程中发现无法使用ReactDOM.findDOMNode这个方法;有什么解决办法呢

React是facebook的项目,然而他们的老大,马克扎尔伯格不是说过自己投资HTML5是极大的失败吗?那我很好奇他对于HTML5相关的项目或者技术的支持力度能有多大,或者说有多久?
一个框架,不是要看它一时的风光,而是未来的可维护性。jQuery为何能够生存十年还屹立不倒?这离不开数万个程序员的你一字我一句的代码维护。
如果真的要制作MVC框架,其实Angular就是个很好的选择了吧,至少人家在1.X版本风靡的前提下,胆敢大刀阔斧的推出2.X版本,这本身就说明了这个团队的精益求精。
此外,项目也必须考虑到后续的维护呀,如果现在用的是昙花一现的框架,那么接手的人遇到了问题,想在网上找个解决方案都不太容易,总不能让他们重新制作一个网站吧?

当然,以上的言论并没有针对阮老师的意思,阮老师对于我而言,是新兴技术的一盏明灯。
只是觉得有些人只顾追逐时尚潮流,却不顾框架/技术是否适合自己适合团队,是否具有可维护性就去讥讽他人,这种行为不太雅观。

求推荐react与现有项目结合的文章

引用happyChong的发言:

求推荐react与现有项目结合的文章

同求

引用瀚海的发言:

React是facebook的项目,然而他们的老大,马克扎尔伯格不是说过自己投资HTML5是极大的失败吗?那我很好奇他对于HTML5相关的项目或者技术的支持力度能有多大,或者说有多久?
如果真的要制作MVC框架,其实Angular就是个很好的选择了吧,至少人家在1.X版本风靡的前提下,胆敢大刀阔斧的推出2.X版本,这本身就说明了这个团队的精益求精。

1.React不是MVC框架,它只能算是MVC中的V
2.Angular1.x和2.x完全是两个不同的框架,也没给出迁移方案,太坑了(2.x)!
3.我们只有对框架的深入理解后,才能为项目技术的选型提供很好的保障

把官方的文档看完,再看这个也是很有收获

正因为追求极致,才推进了前端行业的蓬勃发展。丰富的交互,革命性体验,ReactJS确实比其他普通前端架构更好,特别是移动端,甩Angular几条街。虚拟dom这一概念提高了web性能,部分其它类似的框架都是直接操作DOM,这点不得不服。单看fps,实际测试react在51-60fps, h5在33-55fps。
还有native方面,追求App和wap的统一,react提供了目前最好的方式。
当然实际开发项目里,不只有react,还有和他相关的好多,比如redux,router,为了追求极致,你还可以再上immutable.js。react实现了完全的前后端分离,国内目前也有好多再用了。
颠覆了传统的前端行业,目前在学习,着实惊叹!!!

新兴技术自然有它的优势,太多人不愿花额外的学习成本去了解它,就开始喷了。说啥维护性不好,说啥别人都是跟风,竟然还有人固守jQ,没有学习永远不会有成长。

老师的文章除了Flex篇 其他都是精髓

哪位有测过demo06,为什么我的没报错,正常输出数字?

只想说一句谢谢!

引用码字所得税的发言:

哪位有测过demo06,为什么我的没报错,正常输出数字?

我也是。。。

this.props.promise.then(
value => this.setState({loading: false, data: value}),
error => this.setState({loading: false, error: error}));

请问这段代码是什么意思呢?有什么地方可以深入研究

老实说,初看react这样的代码风格,非常恶心,强迫症患者是在是受不了那种代码无依无靠的感觉

我要发表看法

 «-必填

 «-必填,不公开

 «-我信任你,不会填写广告链接

分类

 

React 入门实例教程

作者: 阮一峰

日期: 2015年3月31日

现在最热门的前端框架,毫无疑问是 React 。

上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑。

React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。

由于 React 的设计思想极其独特,属于革命性创新,性能出众,代码逻辑却非常简单。所以,越来越多的人开始关注和使用,认为它可能是将来 Web 开发的主流工具。

这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App 解决方案。衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机(参见《也许,DOM 不是答案》)。

既然 React 这么热门,看上去充满希望,当然应该好好学一下。从技术角度,可以满足好奇心,提高技术水平;从职业角度,有利于求职和晋升,有利于参与潜力大的项目。但是,好的 React 教程却不容易找到,这一方面因为这项技术太新,刚刚开始走红,大家都没有经验,还在摸索之中;另一方面因为 React 本身还在不断变动,API 一直在调整,至今没发布1.0版。

我学习 React 时,就很苦恼。有的教程讨论一些细节问题,对入门没帮助;有的教程写得不错,但比较短,无助于看清全貌。我断断续续学了几个月,看过二十几篇教程,在这个过程中,将对自己有帮助的 Demo 都收集下来,做成了一个库 React Demos 。

下面,我就根据这个库,写一篇全面又易懂的 React 入门教程。你只需要跟着每一个 Demo 做一遍,就能初步掌握 React 。当然,前提是你必须拥有基本 JavaScript 和 DOM 知识,但是你读完就会发现,React 所要求的预备知识真的很少。

零、安装

React 的安装包,可以到官网下载。不过,React Demos 已经自带 React 源码,不用另外安装,只需把这个库拷贝到你的硬盘就行了。


$ git clone .com:ruanyf/react-demos.git

如果你没安装 git, 那就直接下载 zip 压缩包

下面要讲解的12个例子在各个 Demo 子目录,每个目录都有一个 index.html 文件,在浏览器打开这个文件(大多数情况下双击即可),就能立刻看到效果。

需要说明的是,React 可以在浏览器运行,也可以在服务器运行,但是本教程只涉及浏览器。一方面是为了尽量保持简单,另一方面 React 的语法是一致的,服务器的用法与浏览器差别不大。Demo13 是服务器首屏渲染的例子,有兴趣的朋友可以自己去看源码。

一、HTML 模板

使用 React 的网页源码,结构大致如下。


<!DOCTYPE html>
<html>
  <head>
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
  </head>
  <body>
    <div id="example"></div>
    <script type="text/babel">
      // ** Our code goes here! **
    </script>
  </body>
</html>

上面代码有两个地方需要注意。首先,最后一个 <script> 标签的 type 属性为 text/babel 。这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel" 。

其次,上面代码一共用了三个库: react.js 、react-dom.js 和 Browser.js ,它们必须首先加载。其中,react.js 是 React 的核心库,react-dom.js 是提供与 DOM 相关的功能,Browser.js 的作用是将 JSX 语法转为 JavaScript 语法,这一步很消耗时间,实际上线的时候,应该将它放到服务器完成。


$ babel src --out-dir build

上面命令可以将 src 子目录的 js 文件进行语法转换,转码后的文件全部放在 build 子目录。

二、ReactDOM.render()

ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。


ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('example')
);

上面代码将一个 h1 标题,插入 example 节点(查看 demo01),运行结果如下。

三、JSX 语法

上一节的代码, HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写(查看 Demo02 )。


var names = ['Alice', 'Emily', 'Kate'];

ReactDOM.render(
  <div>
  {
    names.map(function (name) {
      return <div>Hello, {name}!</div>
    })
  }
  </div>,
  document.getElementById('example')
);

上面代码体现了 JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。上面代码的运行结果如下。

JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员(查看 demo03 )。


var arr = [
  <h1>Hello world!</h1>,
  <h2>React is awesome</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('example')
);

上面代码的arr变量是一个数组,结果 JSX 会把它的所有成员,添加到模板,运行结果如下。

四、组件

React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类(查看 demo04)。


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

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

上面代码中,变量 HelloMessage 就是一个组件类。模板插入 <HelloMessage /> 时,会自动生成 HelloMessage 的一个实例(下文的"组件"都指组件类的实例)。所有组件类都必须有自己的 render 方法,用于输出组件。

注意,组件类的第一个字母必须大写,否则会报错,比如HelloMessage不能写成helloMessage。另外,组件类只能包含一个顶层标签,否则也会报错。


var HelloMessage = React.createClass({
  render: function() {
    return <h1>
      Hello {this.props.name}
    </h1><p>
      some text
    </p>;
  }
});

上面代码会报错,因为HelloMessage组件包含了两个顶层标签:h1p

组件的用法与原生的 HTML 标签完全一致,可以任意加入属性,比如 <HelloMessage name="John"> ,就是 HelloMessage 组件加入一个 name 属性,值为 John。组件的属性可以在组件类的 this.props 对象上获取,比如 name 属性就可以通过 this.props.name 读取。上面代码的运行结果如下。

添加组件属性,有一个地方需要注意,就是 class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。

五、this.props.children

this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点(查看 demo05)。


var NotesList = React.createClass({
  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.body
);

上面代码的 NoteList 组件有两个 span 子节点,它们都可以通过 this.props.children 读取,运行结果如下。

这里需要注意, this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。

React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。更多的 React.Children 的方法,请参考官方文档

六、PropTypes

组件的属性可以接受任意值,字符串、对象、函数等等都可以。有时,我们需要一种机制,验证别人使用组件时,提供的参数是否符合要求。

组件类的PropTypes属性,就是用来验证组件实例的属性是否符合要求(查看 demo06)。


var MyTitle = React.createClass({
  propTypes: {
    title: React.PropTypes.string.isRequired,
  },

  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});

上面的Mytitle组件有一个title属性。PropTypes 告诉 React,这个 title 属性是必须的,而且它的值必须是字符串。现在,我们设置 title 属性的值是一个数值。


var data = 123;

ReactDOM.render(
  <MyTitle title={data} />,
  document.body
);

这样一来,title属性就通不过验证了。控制台会显示一行错误信息。


Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.

更多的PropTypes设置,可以查看官方文档

此外,getDefaultProps 方法可以用来设置组件属性的默认值。


var MyTitle = React.createClass({
  getDefaultProps : function () {
    return {
      title : 'Hello World'
    };
  },

  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});

ReactDOM.render(
  <MyTitle />,
  document.body
);

上面代码会输出"Hello World"。

七、获取真实的DOM节点

组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM)。只有当它插入文档以后,才会变成真实的 DOM 。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。

但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性(查看 demo07 )。


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

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

上面代码中,组件 MyComponent 的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。

需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click 事件的回调函数,确保了只有等到真实 DOM 发生 Click 事件之后,才会读取 this.refs.[refName] 属性。

React 组件支持很多事件,除了 Click 事件以外,还有 KeyDown 、CopyScroll 等,完整的事件清单请查看官方文档

八、this.state

组件免不了要与用户互动,React 的一大创新,就是将组件看成是一个状态机,一开始有一个初始状态,然后用户互动,导致状态变化,从而触发重新渲染 UI (查看 demo08 )。


var LikeButton = React.createClass({
  getInitialState: function() {
    return {liked: false};
  },
  handleClick: function(event) {
    this.setState({liked: !this.state.liked});
  },
  render: function() {
    var text = this.state.liked ? 'like' : 'haven\'t liked';
    return (
      <p onClick={this.handleClick}>
        You {text} this. Click to toggle.
      </p>
    );
  }
});

ReactDOM.render(
  <LikeButton />,
  document.getElementById('example')
);

上面代码是一个 LikeButton 组件,它的 getInitialState 方法用于定义初始状态,也就是一个对象,这个对象可以通过 this.state 属性读取。当用户点击组件,导致状态变化,this.setState 方法就修改状态值,每次修改以后,自动调用 this.render 方法,再次渲染组件。

由于 this.props 和 this.state 都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props 表示那些一旦定义,就不再改变的特性,而 this.state 是会随着用户互动而产生变化的特性。

九、表单

用户在表单填入的内容,属于用户跟组件的互动,所以不能用 this.props 读取(查看 demo9 )。


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.body);

上面代码中,文本输入框的值,不能用 this.props.value 读取,而要定义一个 onChange 事件的回调函数,通过 event.target.value 读取用户输入的值。textarea 元素、select元素、radio元素都属于这种情况,更多介绍请参考官方文档

十、组件的生命周期

组件的生命周期分成三个状态:

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实 DOM

React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数。

  • componentWillMount()
  • componentDidMount()
  • componentWillUpdate(object nextProps, object nextState)
  • componentDidUpdate(object prevProps, object prevState)
  • componentWillUnmount()

此外,React 还提供两种特殊状态的处理函数。

  • componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
  • shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用

这些方法的详细说明,可以参考官方文档。下面是一个例子(查看 demo10 )。


var Hello = React.createClass({
  getInitialState: function () {
    return {
      opacity: 1.0
    };
  },

  componentDidMount: function () {
    this.timer = setInterval(function () {
      var opacity = this.state.opacity;
      opacity -= .05;
      if (opacity < 0.1) {
        opacity = 1.0;
      }
      this.setState({
        opacity: opacity
      });
    }.bind(this), 100);
  },

  render: function () {
    return (
      <div style={{opacity: this.state.opacity}}>
        Hello {this.props.name}
      </div>
    );
  }
});

ReactDOM.render(
  <Hello name="world"/>,
  document.body
);

上面代码在hello组件加载以后,通过 componentDidMount 方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。

另外,组件的style属性的设置方式也值得注意,不能写成


style="opacity:{this.state.opacity};"

而要写成


style={{opacity: this.state.opacity}}

这是因为 React 组件样式是一个对象,所以第一重大括号表示这是 JavaScript 语法,第二重大括号表示样式对象。

十一、Ajax

组件的数据来源,通常是通过 Ajax 请求从服务器获取,可以使用 componentDidMount 方法设置 Ajax 请求,等到请求成功,再用 this.setState 方法重新渲染 UI (查看 demo11 )。


var UserGist = React.createClass({
  getInitialState: function() {
    return {
      username: '',
      lastGistUrl: ''
    };
  },

  componentDidMount: function() {
    $.get(this.props.source, function(result) {
      var lastGist = result[0];
      if (this.isMounted()) {
        this.setState({
          username: lastGist.owner.login,
          lastGistUrl: lastGist.html_url
        });
      }
    }.bind(this));
  },

  render: function() {
    return (
      <div>
        {this.state.username}'s last gist is
        <a href={this.state.lastGistUrl}>here</a>.
      </div>
    );
  }
});

ReactDOM.render(
  <UserGist source="https://api.github.com/users/octocat/gists" />,
  document.body
);

上面代码使用 jQuery 完成 Ajax 请求,这是为了便于说明。React 本身没有任何依赖,完全可以不用jQuery,而使用其他库。

我们甚至可以把一个Promise对象传入组件,请看Demo12


ReactDOM.render(
  <RepoList
    promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')}
  />,
  document.body
);

上面代码从Github的API抓取数据,然后将Promise对象作为属性,传给RepoList组件。

如果Promise对象正在抓取数据(pending状态),组件显示"正在加载";如果Promise对象报错(rejected状态),组件显示报错信息;如果Promise对象抓取数据成功(fulfilled状态),组件显示获取的数据。


var RepoList = React.createClass({
  getInitialState: function() {
    return { loading: true, error: null, data: null};
  },

  componentDidMount() {
    this.props.promise.then(
      value => this.setState({loading: false, data: value}),
      error => this.setState({loading: false, error: error}));
  },

  render: function() {
    if (this.state.loading) {
      return <span>Loading...</span>;
    }
    else if (this.state.error !== null) {
      return <span>Error: {this.state.error.message}</span>;
    }
    else {
      var repos = this.state.data.items;
      var repoList = repos.map(function (repo) {
        return (
          <li>
            <a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br/> {repo.description}
          </li>
        );
      });
      return (
        <main>
          <h1>Most Popular JavaScript Projects in Github</h1>
          <ol>{repoList}</ol>
        </main>
      );
    }
  }
});

十二、参考链接

  1. React's official site
  2. React's official examples
  3. React (Virtual) DOM Terminology, by Sebastian Markbåge
  4. The React Quick Start Guide, by Jack Callister
  5. Learning React.js: Getting Started and Concepts, by Ken Wheeler
  6. Getting started with React, by Ryan Clark
  7. React JS Tutorial and Guide to the Gotchas, by Justin Deal
  8. React Primer, by Binary Muse
  9. jQuery versus React.js thinking, by zigomir

(完)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值