读书笔记:Tutorial of React.JS

原文链接

React is all about modular, composable components.

-

In React, components should always represent the state of the view and not only at the point of initialization.

-

该例子的Component结构

  • CommentBox
    • CommentList
      • Comment
    • CommentForm

Component的使用

var CommentBox = React.createClass({
    render: function(){
        return(
<div className="commentBox">
</div>
        );
    }
});

ReactDOM.render(
  <CommentBox />,
  document.getElementById('content')
);

React.createClass()定义component构造器,该方法接受一个JSON 对象,其中键值render定义了关键函数–该函数返回该component对应的HTML结构.

值得注意的是,该HTML结构的语法是一块语法糖,由JSX实现.其相当于

// 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')
);

ReactDom.render
接受两个参数, 一个是markup格式的component变量声明,一个是目标位置, render函数生成的DOM将插入到该目标位置下.

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.

Note that native HTML element names start with a lowercase letter, while custom React class names begin with an uppercase letter.
(注意命名规则)

var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList />
        <CommentForm />
      </div>
    );
  }
});

Component 中可以插入自定义componet

在元素之间传递数据

Let’s create the Comment component, which will depend on data passed in from its parent. Data passed in from a parent component is available as a ‘property’ on the child component. These ‘properties’ are accessed through this.props.
【从父级元素传来的数据,作为自己元素的一个属性使用】
Using props, we will be able to read the data passed to the Comment from the CommentList, and render some markup:

// tutorial4.js
var Comment = React.createClass({
  render: function() {
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        {this.props.children}
      </div>
    );
  }
});

We access named attributes passed to the component as keys on this.props and any nested elements as this.props.children
变量要用花括号括住

(Q:What does it mean by “nested elements”?).
// tutorial5.js
var CommentList = React.createClass({
  render: function() {
    return (
      <div className="commentList">
        <Comment author="Pete Hunt">This is one comment</Comment>
        <Comment author="Jordan Walke">This is *another* comment</Comment>
      </div>
    );
  }
});

通过在标签中添加属性传递参数(如该例子中的<Comment>中的author属性。

使用markdown语法

使用前:这里写图片描述

...
     {this.props.author}
        </h2>
        {this.props.children}  // <===
      </div>
      ...

修改为:

{md.render(this.props.children.toString())}

We need to convertthis.props.children from React’s wrapped text to a raw string that remarkable will understand so we explicitly call toString().
【但这个写法是不work的。】That’s React protecting you from an XSS attack. There’s a way to get around it (but the framework warns you not to use it):
This is a special API that intentionally makes it difficult to insert raw HTML, but for remarkable we’ll take advantage of this backdoor.
需要改写为:

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

  render: function() {
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        <span dangerouslySetInnerHTML={this.rawMarkup()} />
      </div>
    );
  }
});

md.render方法生成的是HTML格式的文本;要使其真正能实现HTML的功能,需要按

 { __html: nameOfYourHTMLContent }

的语法书写。放在一个对象中,key值为__html

传递来自Data Model的数据

此处以内置JSON文件作为简单示例

// CommentList的修改
var CommentList = React.createClass({
  render: function() {
  // 定义动态绑定
    var commentNodes = this.props.data.map(function(comment) {
      return (
        <Comment author={comment.author} key={comment.id}>
          {comment.text}
        </Comment>
      );
    });

    return (
      <div className="commentList">
      //this.props.data.map方法的返回结果是一串**有效的HTML文本**,直接在`render`对应的方法的返回值中作为**变量**使用即可。
        {commentNodes}  // <===Like this!
      </div>
    );
  }
});

this.props.data.map方法接受一个定义了componet及其数据的绑定格式的函数。该函数的参数就是数据的item

// CommenBox的修改
var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        // 数据首先到达父级元素CommentBox,
        // 在子元素CommentList中作为属性使用
        <CommentList data={this.props.data} /> 
        <CommentForm />
      </div>
    );
  }
});

ReactDOM.render(
  <CommentBox data={data} />,
  document.getElementById('content')
);

Componet 的属性data中绑定数据源:在ReactDOM.render中修改 data={nameOfDataSourceVariable}

绑定服务器上的数据源

ReactDOM.render(
  <CommentBox url="/api/comments" />,
  document.getElementById('content')
);

使用Componenturl属性。结合server端的代码使用。

app.get('/api/comments', function(req, res) {
  fs.readFile(COMMENTS_FILE, function(err, data) {
    if (err) {
      console.error(err);
      process.exit(1);
    }
    res.json(JSON.parse(data));
  });
});
...
var COMMENTS_FILE = path.join(__dirname, 'comments.json');

数据的请求是最后在ReactDOM.render函数中进行的,任何component的声明都只提供了一个空框架/模型

使用Component的state属性实现交互

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.

// tutorial12.js
var CommentBox = React.createClass({
  getInitialState: function() {
    return {data: []};
  },
  render: function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    );
  }
});

getInitialState(): executes exactly once during the lifecycle of the component and sets up the initial state of the component. When the server fetches data, we will be changing the comment data we have.

getInitialState和render一样,都是固定语法

实现数据的实时更新

We’re going to use jQuery to make an asynchronous request to the server we started earlier to fetch the data we need

再次修改CommentBox,添加componentDidMount函数:(注意componentDidMount也是固定语法)

// tutorial13.js
var CommentBox = React.createClass({
  getInitialState: function() {
    return {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 (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm />
      </div>
    );
  }
});

componentDidMount
核心代码是this.setState()。它做了两件事:1.从服务器取得最新数据并覆盖旧的;2.让UI自动更新。
传参语法:{data: nameOfCallBackParams}

优化代码,将AJAX请求数据的部分分离出来:

...
  componentDidMount: function() {
  // AJAX is wrapped up in a func.
    this.loadCommentsFromServer();  
   /* call AJAX when the component is first loaded and every 2 seconds after that. */
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  },
...
ReactDOM.render(

  <CommentBox url="/api/comments" pollInterval={2000} />,
  document.getElementById('content')
);

设置请求间隔:在render函数中使用pollInterval属性设置:pollInterval={numberOfMiliseconds}

实现用户数据输入(表单提交)

区别于传统DOM的处理方式

【传统DOM带来的问题】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. This is not ideal as the state of the view will differ from that of the component.
we will be usingthis.stateto 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 <input> elements with a value set are called controlled components.

修改CommentForm

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});
  },
  ...
<input    type="text"
          placeholder="Say something..."
          value={this.state.text}
          onChange={this.handleTextChange}
        />

注意setState语法: this.setState({nameOfProperty: nameOfCallbackParam.target.value});
onChange是一个event.

实现表单提交

Let’s make the form interactive. When the user submits the form, we should clear it,
submit a request to the server,
and refresh the list of comments.
To start, let’s listen for the form’s submit event and clear it.

修改CommentForm:

  handleSubmit: function(e) {
    e.preventDefault();
    var author = this.state.author.trim();
    var text = this.state.text.trim();
    /*.trim()?*/
    if (!text || !author) {
      return;
    }
    // TODO: send request to the server
    /*clear the form after submission*/
    this.setState({author: '', text: ''});
  },
  ...
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
      ...

formonSubmit监听了提交事件。

Call preventDefault() on the event to prevent the browser’s default action of submitting the form.

实现列表刷新:子元素传数据到父元素

It makes sense to do all of this logic in CommentBox since CommentBox owns the state that represents the list of comments.
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, binding it to the child’s onCommentSubmit event. Whenever the event is triggered, the callback will be invoked.
【用回调函数的方式,实现从子元素传递数据到父元素】

修改CommentBox的render:

  handleCommentSubmit: function(comment) {
    // TODO: submit to the server and refresh the list
  },
        /* LOOK AT HERE ↓ */
    this.props.onCommentSubmit({author: author, text: text});
    this.setState({author: '', text: ''});
  },
render: 
...
function() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        /* LOOK AT HERE ↓ */
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }

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:

修改CommentForm:

...
 handleSubmit: function(e) {
    e.preventDefault();
    var author = this.state.author.trim();
    var text = this.state.text.trim();
    if (!text || !author) {
      return;
    }
    /* 父级传来的回调函数通过
    this.props.nameOfCallBackMethod来调用!
LOOK AT HERE ↓ */
    this.props.onCommentSubmit({author: author, text: text});
    this.setState({author: '', text: ''});
  },
...

得到CommentForm的数据之后,CommentBox就可以将数据提交到服务器(url)更新列表了:

// CommentBox
 handleCommentSubmit: function(comment) {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      type: 'POST',
      //  发送数据的ajax请求
      data: comment, 
      success: function(data) {
        this.setState({data: data});
      }...);
  },

将回调结果’comment’写入键值’data’。

优化列表刷新:本地刷新

In  CommentBox

 handleCommentSubmit: function(comment) {
    var comments = this.state.data;
    // comments是当前的数据大数组

    comment.id = Date.now();
    // 将新的comment添加(concat)到comments中
    var newComments = comments.concat([comment]);
    // 本地手动更新
    this.setState({data: newComments});
    $.ajax({
    ...

总结

  • 学会了component的基本使用;
  • 数据和component的绑定;
  • 数据源的绑定(本地/服务器)。
  • JSX作为语法糖的使用。
  • 运用元素的prop(properties)进行数据传递,以及在此之上利用回调函数进行从子元素到父元素数据传递
  • 使用markdown渲染文本。
Q:.state和.props在数据传递上的区别是什么?

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】是不会变动的,在生成时初始化并不再更改。
this.state is private to the component and can be changed by calling this.setState(). When the state updates, the component re-renders itself.

动手

最近刚好在学SQL,可以用react.js做一个数据可视化的工具。

拓展

Forms Article:进阶使用Controlled Components
automatically binds :事件绑定
thinking in react

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值