React-Tutorial学习笔记

1.My first component


We will have the following component structure:

-CommentBox
  -CommentList
    -Comment
  -CommentForm
//index.html
//tutorial1.js
var CommentBox = React.createClass({
  render:function(){
    return (
      
Hello , World !
); } }); ReactDOM.render( , document.getElementById('content') );
//JSX syntax
// tutorial1-raw.js
var CommentBox = React.createClass({displayName: 'CommentBox',
  render: function() {
    return (
      React.createElement('div', {className: "commentBox"},
        "Hello, world! I am a CommentBox."
      )
    );
  }
});
ReactDOM.render(
  React.createElement(CommentBox, null),
  document.getElementById('content')
);

(1)Note that native HTMLelement names start with a lowercase letter , while customReactclass names begin with an uppercase letter.
译:HTML 标签以小写字母开头,而 React 组件 以大写字母开头。
(2)We pass some methods in a JavaScript object to React.creatClass()to create a new React component . The most important of these methods is called render which returns a tree of React components that will eventually render to HTML.
译:我们在JS 对象中传递一些方法到React.createClass()来创建一个新的React 组件。其中最重要的方法是 render ,他返回一个 React 组件树,最终将渲染到HTML
(3)The

tags are not actual DOM nodes; they are instantiations of React div components.You can think of these as markers or pieces of data that React knows how to handle.
(4)You do not have to return basic HTML. You can return a tree of components that you (or someone else) built. This is what makes React composable(可组合): a key tenet of maintainable frontends.(可维护前端的宗旨)
(5)ReactDOM.render() instantiates(实例化) the root component, starts the framework(框架), and injects( 注入、添加 ) the markup into a raw DOM element, provided as the second argument(参数).
(6)It is important that ReactDOM.render remain at the bottom of the script for this tutorial. ReactDOM.render should only be called after the composite components(复合组件) have been defined.

2.Composing components


var CommentBox = React.createClass({
  render: function() {
    return (
      

Comments

); } });

Notice how we're mixing HTML tags and components we've built. HTML componentsare regular React components, just like the ones you define, with one difference. The JSX compiler will automatically rewrite HTML tags to React.createElement(tagName) expressions and leave everything else alone. ( JSX 编译器会自动将HTML标签重写为React.createElement(tagname)表达式,并留下其余的一切 )This is to prevent the pollution of the global namespace.(防止全局命名空间的污染)

3.Using props


var Comment = React.createClass({
  render: function() {
    return (
      

{this.props.author}

{this.props.children}
); } });

(1)Data passed in from a parent component is available as a 'property' (属性)on the child component
These 'properties' are accessed through this.props.
(2)By surrounding a JavaScript expression in braces(大括号) inside JSX (as either an attribute or child), you can drop text or React components into the tree. We access named attributes passed to the componentas keys on this.props and any nested elements as this.props.children.(我们通过this.props上的键 或 任何像this.props.children的嵌套元素 访问传递给组件的命名属性)

4.Component Properties(组件属性)


// tutorial5.js
var CommentList = React.createClass({
  render: function() {
    return (
      
This is one comment This is *another* comment
); } });

Note that we have passed some data from the parent CommentListcomponent to the child Commentcomponents.

5.Adding Markdown

// tutorial7.js
var Comment = React.createClass({
  rawMarkup: function() {
    var md = new Remarkable();
    var rawMarkup = md.render(this.props.children.toString());
    return { __html: rawMarkup };
  },

  render: function() {
    return (
      

{this.props.author}

); } });

This is a special API that intentionally makes it difficult to insert raw HTML, but for remarkable we'll take advantage of this backdoor.
Remember: by using this feature you're relying on remarkable to be secure. In this case, remarkable automatically strips HTML markup and insecure links from the output.

6.Hook up the data model(挂钩数据模型)


So far we've been inserting the comments directly in the source code. Instead, let's render a blob of JSON data into the comment list. Eventually this will come from the server, but for now, write it in your source:

// tutorial8.js
var data = [
  {id: 1, author: "Pete Hunt", text: "This is one comment"},
  {id: 2, author: "Jordan Walke", text: "This is *another* comment"}
];

We need to get this data into CommentList in a modular way(模块化的方式). Modify(修改) CommentBox and theReactDOM.render() call to pass this data into theCommentList via(通过) props:

// tutorial9.js
var CommentBox = React.createClass({
  render: function() {
    return (
      

Comments

//Modify CommentBox to get this data into CommentList
); } }); ReactDOM.render( , //Modify ReactDOM.render() document.getElementById('content') );

Now that the data is available in the CommentList, let's render the comments dynamically:

var CommentList = React.createClass({
  render:function(){
    var commentNodes = this.props.data.map(function(comment){
      return(
        
          {comment.text}
        
      );
    });
    return(
      
{commentNodes}
); } });

7.Fetching from the server


Let's replace the hard-coded data with some dynamic data from the server. We will remove the data prop and replace it with a URL to fetch:

// tutorial11.js
ReactDOM.render(
  ,
  document.getElementById('content')
);

This component is different from the prior components because it will have to re-render itself.The component won't have any data until the request from the server comes back, at which point the component may need to render some new comments.
Note: the code will not be working at this step.

8.Reactive state


So far, based on its props, each component has rendered itself once.props are immutable(不可变): they are passed from the parent and are "owned" by the parent(props 从parent而来,归 parent 所有)

To implement (执行)interactions(互动), we introduce mutable(可变的) state to the component. this.state is private to the component and can be changed by calling this.setState(). When the state updates, the component re-renders itself.

render() methods are written declaratively as functions of this.props and this.state. The framework guarantees the UI is always consistent with the inputs.(框架保证UI总是与输入保持一致)

When the server fetches data(服务器获取数据), we will be changing the comment data we have. Let's add an array of comment data to theCommentBoxcomponent as its state:

var CommentBox = React.createClass({
  getInitialState:function(){     //getInitialState : function(){ } 
    return { data: [] };
  },
  render:function(){
    return(
      

Comments

//data={this.state.data}
); } });

getInitialState() executes exactly once during the lifecycle of the component and sets up the initial state of the component.(getInitialState()在组件的生命周期中执行一次,并且设置组件的初始状态)

9.Updating state


When the component is first created, we want to GET some JSON from the server and update the state to reflect the latest data. We're going to use jQuery to make an asynchronous request (异步请求)to the server we started earlier(之前启动的服务器) to fetch the data we need. The data is already included in the server you started (based on the comments.json file), so once it's fetched, this.state.data will look something like this:

//comments.json
[
   {"id" : "1" , "author" : "Pete Hunt" , "text" : "This is one comment" },
   {"id" : "2" , "author" : "Angela Ma" , "text" : "This is my comment" }
]
var  CommentBox  = React.createClass({
  getInitialState:function(){
    return{[data:data]};
  },
  
  componentDidMount:function(){
    $.ajax({
      url : this.props.url,
      dataType :'json',
      cache:false,
      success:function(data){
        this.setState({data:data});
      }.bind(this),
      error:function(xhr,status,err){
        console.error(this.props.url,status,err.toString());
      }.bind(this)
    });
  },

  render:function(){
    return(
      

Comment

); } });

Here, componentDidMount is a method called automatically by React after a component is rendered for the first time. (componentDidMount是组件第一次渲染后,由React自动调用的方法)
The key to dynamic updates is the call to this.setState().(动态更新的关键是 this.setState()的调用。) We replace the old array of comments with the new one from the server and the UI automatically updates itself.( 我们用服务器中的新数组替换旧数组的内容,UI自动更新自己。)
Because of this reactivity, it is only a minor change to add live updates.(由于这种反应性,添加实时更新只是很小的改变。)

var CommentBox=React.createClass({
          loadCommentsFromServer:function(){        //!!!!!
            $.ajax({
              url:this.props.url,
              dataType:'json',
              cache:false,
              success:function(data){
                this.setState({data:data});
              }.bind(this),
              error:function(xhr,status,err){
                console.error(this.props.url,status,err.toString());
              }.bind(this)
            });
          },
          getInitialState:function(){
            return {data:[]};
          },
          componentDidMount:function(){   // !!!!
            this.loadCommentsFromServer();
            setInterval(this.loadCommentsFromServer,this.props.pollInterval);
          },
          render:function(){
            return(
              

Comments

); } }); ReactDOM.render( , //!!! document.getElementById('content') );

All we have done is move the AJAX call to a separate method and call it when the component is first loaded and every 2 seconds after that.(我们所做的是把AJAX调用封装成单独的方法,并在组件第一次加载时调用它)

10.Adding new comments


Now it's time to build the form. Our CommentForm component should ask the user for their name and comment text and send a request to the server to save the comment.(向服务器发送请求来保存这些内容)

// tutorial15.js
var CommentForm = React.createClass({
  render: function() {
    return (
      
); } });

Controlled components(受控组件)

With the traditional DOM, input elements are rendered and the browser manages the state (its rendered value). As a result, the state of the actual DOM will differ from that of the component.(在传统的DOM中,input元素被渲染,浏览器管理状态(渲染值),因此,实际的DOM状态(输入值)与组件的状态(初始值)不同)。

In React, components should always represent the state of the view and not only at the point of initialization.(在``React`中,组件始终表示视图的状态,而不仅仅是初始值)

Hence, we will be using this.state to save the user's input as it is entered. We define an initial state with two properties author and text and set them to be empty strings.
In our elements, we set the value prop to reflect the state of the component and attach onChange handlers to them.
These elements with a value set are called controlled components.(具有value值的Input元素,称为受控组件)

// tutorial16.js
var CommentForm = React.createClass({
  getInitialState: function() {
    return {author: '', text: ''};
  },
  handleAuthorChange: function(e) {
    this.setState({author: e.target.value});
  },
  handleTextChange: function(e) {
    this.setState({text: e.target.value});
  },
  render: function() {
    return (
      
); } });

Events
React attaches event handlers to components using a camelCase naming convention.(驼峰命名法)
React.createClass(...) automatically binds each method to its component instance, obviating the need for explicit binding.(React.createClass(...)自动绑定每个方法到它的组件实例,避免了显式绑定的需要 。)

Submitting the form

To start, let's listen for the form's submit event and clear it.

// tutorial17.js
var CommentForm = React.createClass({
  getInitialState: function() {
    return {author: '', text: ''};
  },
  handleAuthorChange: function(e) {
    this.setState({author: e.target.value});
  },
  handleTextChange: function(e) {
    this.setState({text: e.target.value});
  },
  handleSubmit: function(e) {      //!!!
    e.preventDefault();
    var author = this.state.author.trim();
    var text = this.state.text.trim();
    if (!text || !author) {
      return;
    }
    // TODO: send request to the server
    this.setState({author: '', text: ''});
  },
  render: function() {
    return (
      
//!!!
); } });

Call preventDefault() on the event to prevent the browser's default action of submitting the form.(阻止浏览器提交表单的默认行为)

Callbacks as props
When a user submits a comment, we will need to refresh the list of comments to include the new one. It makes sense to do all of this logic in CommentBox since CommentBox owns the state that represents the list of comments.(在CommentBox中执行这个逻辑是有意义的,因为CommentBox持有评论列表的状态)

We need to pass data from the child component back up to its parent.
We do this in our parent's render method by passing a new callback (handleCommentSubmit) into the child(我们通过一个新的回调handleCommentSubmit传递给子组件), binding(绑定) it to the child's onCommentSubmit event.
Whenever the event is triggered, the callback will be invoked:(当事件被触发,回调将被调用)

// tutorial18.js
var CommentBox = React.createClass({
  loadCommentsFromServer: function() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  handleCommentSubmit: function(comment) {    //!!!
    // TODO: submit to the server and refresh the list
  },
  getInitialState: function() {
    return {data: []};
  },
  componentDidMount: function() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);  
  },
  render: function() {
    return (
      

Comments

//!!!
); } });

Now that CommentBox has made the callback available to CommentForm via the onCommentSubmit prop, the CommentForm can call the callback when the user submits the form:

// tutorial19.js
var CommentForm = React.createClass({
  getInitialState: function() {
    return {author: '', text: ''};
  },
  handleAuthorChange: function(e) {
    this.setState({author: e.target.value});
  },
  handleTextChange: function(e) {
    this.setState({text: e.target.value});
  },
  handleSubmit: function(e) {
    e.preventDefault();
    var author = this.state.author.trim();
    var text = this.state.text.trim();
    if (!text || !author) {
      return;
    }
    this.props.onCommentSubmit({author: author, text: text});   //!!!
    this.setState({author: '', text: ''});
  },
  render: function() {
    return (
      
); } });

Now that the callbacks are in place, all we have to do is submit to the server and refresh the list:

var CommentBox = React.createClass({
  loadCommentsFromServer: function() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  handleCommentSubmit: function(comment) {    //!!!
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      type: 'POST',
      data: comment,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  getInitialState: function() {
    return {data: []};
  },
  componentDidMount: function() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  },
  render: function() {
    return (
      

Comments

); } });

11.Optimization: optimistic updates(优化)

Our application is now feature complete but it feels slow to have to wait for the request to complete before your comment appears in the list. (功能齐全,但是评论出现在列表之前需要等待请求完成,所以感觉很慢)
We can optimistically add this comment to the list to make the app feel faster.(我们可以乐观地添加这个评论到列表,使应用程序感觉更快。)

// tutorial21.js
var CommentBox = React.createClass({
  loadCommentsFromServer: function() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  handleCommentSubmit: function(comment) {
    var comments = this.state.data;    //!!!
    // Optimistically set an id on the new comment. It will be replaced by an
    // id generated by the server. In a production application you would likely
    // not use Date.now() for this and would have a more robust system in place.
    comment.id = Date.now();   //!给新的comment设置id,它将被服务器生成的id-Date.now()替换,希望之后不要使用Date.now()
    var newComments = comments.concat([comment]);   //!!!
    this.setState({data: newComments});   //!!!
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      type: 'POST',
      data: comment,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        this.setState({data: comments});    //!!!
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },
  getInitialState: function() {
    return {data: []};
  },
  componentDidMount: function() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  },
  render: function() {
    return (
      

Comments

); } });

Congrats!
We have just built a comment box in a few simple steps.

你可能感兴趣的:(React-Tutorial学习笔记)