[从零开始react002] component基本用法

1 什么是component

设计接口的时候,把通用的设计元素(按钮,表单框,布局组件等)拆成接口良好定义的可复用的组件。 这样,下次开发相同界面程序时就可以写更少的代码,也意义着更高的开发效率,更少的 Bug 和更少的程序体积。 Thinking in react 里面举了一个React 构建可搜索的商品数据的例子。

接下来我们将创建一个好玩的component来全面了解它的组成和运行机制, 回顾一下我们在001中的 public/index.html 它是直接引用了webpack生成的client.min.js(console里面打印文字)。 这样一点都不好玩,接来下我们从头开始构造一个完成的index.hmtl页面.

2. 定义html和引用的js入口

<html>
  <head>
    <meta charset="utf-8">
    <title>React‘s Component Example</title>
  </head>
  <body>
      <div id="app"></div>
    <script src="client.min.js" type="text/javascript"></script>
  </body>
</html>

在html里面定义一个id= "app" 的 div标签并引用client.min.js,这个html就是我们的入口。 时刻记得client.min.js是来自于webpack的entry: src/client.js 里面生成的。 所以我们就通过client.js来操作html中的div构建页面。

import React from ‘react‘;
import ReactDom from "react-dom";
import Layout from "./component/Layout";
const app = document.getElementById("app");
ReactDom.render(<Layout />, app);

看懂上面的语法你应该要学会的是基本的JSX语法, 看完后问自己2个问题:

1. 为什么要使用JSX语法?
2. JSX和HTML的差异是什么?

这里你只需要知道 <Layout /> 是引用Layout Component。

页面的构成应该是(页面就是一个Tree,不要什么都堆在一起)

–Layout
  -—Header
       –title
   -—Body
   -—Footer

2.1. 定义最上层的Layout

import React from ‘react‘;
import Footer from "./Footer";
import Header from "./Header";

export default class Layout extends React.Component {
    render() {
        return (<div>
                <Header />
                <Footer />
                </div>);
    };
}

component 必须要定义的render函数,render是核心, 它组装生成这个组件的HTML结构(使用原生HTML标签或者子组件)。

当调用的时候,会检测 this.props 和 this.state,返回一个单子级组件(注意只能是单个,所以我们用div把header和footer包了一层)。

该子级组件可以是虚拟的本地 DOM 组件(比如 <div /> 或者 React.DOM.div()),也可以是自定义的复合组件。

你也可以返回 null 或者 false 来表明不需要渲染任何东西。 实际上,react 渲染一个 <noscript> 标签来处理当前的差异检查逻辑。当返回 null 或者 false 的时候,this.getDOMNode() 将返回 null。

render() 函数应该是纯粹的,也就是说该函数不修改组件state, 每次调用都返回相同的结果,不读写 DOM 信息,也不和浏览器交互(例如通过使用setTimeout)。 如果需要和浏览器交互,在 componentDidMount() 中或者其它生命周期方法中做这件事。保持 render() 纯粹,可以使服务器端渲染更加切实可行,也使组件更容易被理解。

2.2. 定义Footer

import React from "react";
export default class Footer extends React.Component {
    render() { return(<div> <h3> Footer: Building UI is a funny thing </h3> </div>);}
}

只是简单的把自己用h1显示出来

2.3. 定义Header

import React from "react";
import Title from "./Title";
export default class Header extends React.Component {
    render() {
        return(<div>
               <Title />
               <h3> Header: Component create a new world </h3>
               </div> );
    }
}

我们就可以看到它引用了Title

2.4. 定义Title

import React from "react";
export default class Title extends React.Component {
    render() {
        return(<div>
                <h2> Title: Everything is Component  </h2>
                </div>
        );
    }
}

这上面都是静态的东西,根本就看不出component有什么值得炫酷的地方,只是显示了 title header footer。 离标题Title随着我们给定的输入框的文字变化还差得远 不过在开始之前, 应该先预习一下component api弄明白它的state和prop。

1. props就是component的属性,由外部通过JSX属性传入设置,一旦初始设置完成,就可以认为this.props是不可更改的,

所以不要轻易更改设置this.props里面的值(虽然对于一个JS对象你可以做任何事)。

2. state是component的当前状态,可以把component简单看成一个“状态机”,根据状态state 呈现不同的UI展示。

一旦状态(数据)更改,component就会自动调用render重新渲染UI,这个更改的动作会通过 this.setState方法来触发。

3. 一条原则:让component尽可能地少状态。这样组件逻辑就越容易维护。当更改这个状态(数据)需要更新组件UI的就可以认为是state

4. 无状态compoent, 我们上面的4个就是这种无状态的。

你也可以用纯粹的函数来定义无状态的组件(stateless function), 这种组件没有状态,没有生命周期,只是简单的接受props 渲染生成DOM 结构。无状态组件非常简单,开销很低,如果可能的话尽量使用无状态组件。

3. 有状态的component

我们要做的就是Layout把要改变的title和改变title的函数一级一级的传给下级的component 这必须要用到component间是怎么通信的

3.1 父子间通信就是通过props属性来传递, 在父component中给子component设置props,然后子component就可以访问到父component的数据和方法.

3.2 非父子间通信使用全局事件Pub/Sub模式,在componentDidMount里面订阅事件,在 componentWillUnmount里面取消订阅,当收到事件触发的时候调用setState更新UI。

这里我们只用到了父子间通信。

在Layout中把title和changetitle的函数都传给header component, 注意传给下一级方法时一定要显示的表明这个方法来自己于哪里 — bind(this)操作。

import React from ‘react‘;
import Footer from "./Footer";
import Header from "./Header";

export default class Layout extends React.Component {
    constructor(){
        super();
        this.state = {title: "welcome"};
    }
    changeTitle(title){
        this.setState({title: title});
    }
    render() {
        return (<div>
                <Header changeTitle={this.changeTitle.bina(this)} title={this.state.title}/>
                <Footer />
                </div>);
    };
}

Header接收到这个Title后如何处理

import React from "react";
import Title from "./Title";
export default class Header extends React.Component {
    handleChange(e) {
        const title = e.target.value;
        this.props.changeTitle(title);
    }
    render() {
        return(<div>
               <Title title={this.props.title}/>
               <input value={this.props.title} onChange= {this.handleChange.bind(this)}/>
               <input value={this.props.title} onChange= {this.handleChange.bind(this)}/>
               </div> );
    }
}

Header把title又往下传递给应该处理的Title Component, 自己又建了两个输入框,初始值为title,然后再定义一个onChange事件

Title接到title后只需要把它显示成title就行了,这就是它要做的事!

import React from "react";
export default class Title extends React.Component {
    render() {
        return(<div>
               <h2> {this.props.title}  </h2>
                </div>
        );
    }
}

总结上面的流程就是Layout把自己changeTitle的方法和title的属性先传给Header,Header再把他们传给Title。

这里发生了一件非常奇妙的事,我们在Layout Header Title 里都有state, 我们通过input输入框输入文字触发Layout的SetState方法, 结果所有的State里面的title都跟着变化啦,这就是virtual DOM的好处,react把操作真实DOM的操作又封装了一层,让我们不用操心哪一个DOM应该更新这种事。 JS很快,慢的只是刷新DOM里面的tree, 而且繁锁, 但是react把刷新DOM的操作透明了,简直太贴心啦。

我们打开chrome developer tool 里面timeline的 Rendering下的Enable paint flashing,看看我们在输入的时候是哪一些DOM刷新啦。

可以看出它只是刷新应该刷新的Title Header和input

通过这一章节我们掌握到了什么是component, component的state props及他们之前的区别,父子component之间如何通信。

4 扩展阅读

Web应用组件化的权衡

时间: 2024-11-09 04:02:22

[从零开始react002] component基本用法的相关文章

salesforce 零基础学习(六十一)apex:component简单使用以及图片轮转播放的实现

有的时候,我们项目有可能有类似需求:做一个简单的图像轮转播放功能,不同的VF页面调用可以显示不同的图片以及不同的图片描述.这种情况,如果在每个页面单独处理相关的图像轮转播放则显得代码特别冗余,此种情况下适合使用apex:component实现,将图像轮转的功能做成一个组件,图像的URL以及图像的描述信息可以作为参数传递进来,不同的VF可以放置不同的图像 URLS 和描述信息. 一.apex:component简单用法介绍: apex:component作为预定义的组件通常需要VF页面进行相关传值

JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)

阅读目录 一.为什么组件很重要 二.Vue里面的组件基础知识 1.组件的概念 2.组件原理 3.组件使用 三.封装自己的Component 1.使用Component封装bootstrapTable 2.封装select 3.查看其他Vue框架源码 四.总结 正文 前言:转眼距离上篇 JS组件系列--又一款MVVM组件:Vue(一:30分钟搞定前端增删改查) 已有好几个月了,今天打算将它捡起来,发现好久不用,Vue相关技术点都生疏不少.经过这几个月的时间,Vue的发展也是异常迅猛,不过这好像和博

Play1+angularjs+bootstrap ++ (idea + livereload)

我的web开发最强组合:Play1+angularjs+bootstrap ++ (idea + livereload) 时间 2012-12-26 20:57:26  Freewind.me原文  http://freewind.me/blog/20121226/1167.html 首先说明我开发web的情况: 个人开发 前后端全部自己搞定 网站类型多为传统多页面程序 注重开发效率 Javascritp能力不强 美术细胞很少 由于每个人情况不同,选择技术及方案的重点也不同,所以内容仅供参考.对

JavaScript 参考教程

JavaScript 是使用“对象化编程”的,或者叫“面向对象编程”的.所谓“对象化编程”,意思是把 JavaScript 能涉及的范围划分成大大小小的对象,对象下面还继续划分对象直至非常详细为止,所有的编程都以对象为出发点,基于对象.小到一个变量,大到网页文档.窗口甚至屏幕,都是对象.这一章将“面向对象”讲述 JavaScript 的运行情况. 对象的基本知识 对象是可以从 JavaScript“势力范围”中划分出来的一小块,可以是一段文字.一幅图片.一个表单(Form)等等.每个对象有它自己

vue/cli3 + typescript 中watch prop component computed 的用法

    第一步:引入: import {Component,Prop,Watch, Vue} from 'vue-property-decorator';//注意点: 首字母都是大写 第二步:用法 1.component @Component({ components:{ //组件的名字 }})export default class formall extends Vue {2.prop @Prop() private visible:boolean = false; //visible 为父

关于Spring注解 @Service @Component @Controller @Repository 用法

@Component 相当于实例化类的对象,其他三个注解可以理解为@Component的子注解或细化. 在annotaion配置注解中用@Component来表示一个通用注释用于说明一个类是一个spring容器管理的类,此类将有spring扫描并加入容器参与ioc.即就是该类已经拉入到spring的管理中了. 通过在 classpath 中通过自动扫描方式把组建纳入 spring 容器管理. 要使用自动扫描机制我们需要打开一下配置信息: Bean.xml代码    <?xml version= 

Lookup component 用法

Lookup component 类似于Tsql的join子句, select a.* ,b.* from dbo.tis a left join dbo. tdes b on a.code=b.code Lookup component的组成分析 两个输入,一个是上游数据流的输入 dbo.tis,一个是要查找的数据集 dbo.tdes: 两个输出,一个是输出匹配成功的数据,一个是输出匹配不成功的数据.上游数据流的一行数据跟整个查找集进行匹配,如果匹配成功,那么输出匹配成功的数据,否则,输出匹配

Script component 用法

在SSIS中,可以使用C#编写脚本,这是十分激动人心的事,能够使用C#代码,使得Script Component无所不能. 第一部分:组件简介Script Component 有三种类型:Source, Destination and Transformation 1,每种类型的脚本,都有两种类型的参数:ReadOnly 和ReadWrite,在脚本中可以使用 this.Variables.VariableName 来获取或设置参数变量的值 示例:创建四个Variable,并传递给Script

Delphi - GetUserNameEx(学一下导出Windows API,以及Array Char充当缓冲区的用法,下标必须从零开始)

(* * Author : http://www.michael-puff.de * Date : 2006-03-29 * License : PUBLIC DOMAIN *) function GetUserNameEx(NameFormat: DWORD; lpNameBuffer: LPSTR; var nSize: DWORD): Boolean; stdcall; external 'secur32.dll' Name 'GetUserNameExA'; function GetLo