React组件、组件封装、组件通信

React

目标

  • 了解组件以及组件的封装

  • 组件通信

  • children

  • defaultProps

React

React.js 是一个帮助你构建页面 UI 的库。React.js 将帮助我们将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,就成了我们的页面。

一个组件的显示形态和行为有可能是由某些数据决定的。而数据是可能发生改变的,这时候组件的显示形态就会发生相应的改变。而 React.js 也提供了一种非常高效的方式帮助我们做到了数据和组件显示形态之间的同步。

React.js 不是一个框架,它只是一个库。它只提供 UI (view)层面的解决方案。在实际的项目当中,它并不能解决我们所有的问题,需要结合其它的库,例如 Redux、React-router 等来协助提供完整的解决方法。

  • 模块化:从 代码 的角度,去分析问题,把我们编程时候的业务逻辑,分割到不同的模块中来进行开发,这样能够方便代码的重用;

  • 组件化:从 UI 的角度,去分析问题,把一个页面,拆分为一些互不相干的小组件,随着我们项目的开发,我们手里的组件会越来越多,最后,我们如果要实现一个页面,可能直接把现有的组件拿过来进行拼接,就能快速得到一个完整的页面, 这样方便了UI元素的重用;组件是元素的集合体。

vue 组件化与 React组件化

1、Vue是如何实现组件化的:.vue 组件模板文件,浏览器不识别这样的.vue文件,所以,在运行前,会把 .vue 预先编译成真正的组件;

  • template: UI结构

  • script: 业务逻辑和数据

  • style: UI的样式

2、React如何实现组件化:在React中实现组件化的时候,根本没有像 .vue 这样的模板文件,而是,直接使用JS代码的形式,去创建任何你想要的组件;

  • React中的组件,都是直接在 js 文件中定义的;

  • React的组件,并没有把一个组件 拆分为 三部分(结构、样式、业务逻辑),而是全部使用JS来实现一个组件的;(也就是说:结构、样式、业务逻辑是混合在JS里面一起编写出来的)

React中的核心概念

  • 虚拟DOM(Virtual Document Object Model)

  • DOM的本质是什么:就是用JS表示的UI元素

  • DOM和虚拟DOM的区别:

    • DOM是由浏览器中的JS提供功能,所以我们只能人为的使用 浏览器提供的固定的API来操作DOM对象;

    • 虚拟DOM:并不是由浏览器提供的,而是我们程序员手动模拟实现的,类似于浏览器中的DOM,但是有着本质的区别;

  • 为什么要实现虚拟DOM:

  • 什么是React中的虚拟DOM:

  • 虚拟DOM的目的:

 DOM      DOM
​
​
 {
 html:
 head:
 body:{
 Navigation:na
 content:content
 }
​
 }
​
 class  Navigation {
 constructor() {
​
 }
​
 render(){
 <img />
 <p></p>
 }
 }
​
 var na = new Navigation();```

*   Diff算法

*   tree diff:新旧DOM树,逐层对比的方式,就叫做 tree diff,每当我们从前到后,把所有层的节点对比完后,必然能够找到那些 需要被更新的元素;

*   component diff:在对比每一层的时候,组件之间的对比,叫做 component diff;当对比组件的时候,如果两个组件的类型相同,则暂时认为这个组件不需要被更新,如果组件的类型不同,则立即将旧组件移除,新建一个组件,替换到被移除的位置;

*   element diff:在组件中,每个元素之间也要进行对比,那么,元素级别的对比,叫做 element diff;

*   key:key这个属性,可以把 页面上的 DOM节点 和 虚拟DOM中的对象,做一层关联关系;

#### 配置和安装 React

##### 使用 create-react-app 脚手架安装 React 开发环境

用 React 官网提供的 create-react-app 来搭建非常简单:

1、配置安装 npm

```npm -v```

2、安装 create-react-app

```npm install -g create-react-app```

3、创建 React 项目

```//cd 创建项目的目录
cd 项目路径
​
//创建
create-react-app 项目名称```

这条命令会帮我们构建一个叫 react_test 的工程,并且会自动地帮助我们安装所需要的依赖,现在只需要安静地等待它安装完。

4、启动工程开始项目

```//cd 到项目路径
cd react_test
​
//npm 启动工程
npm start```

##### 手动创建 React 开发环境

面对复杂的项目, 入门级的构建工具, 是远远不够的, 我们这里从零开始, 用webpack, 手动配置一个独立的React开发环境, 开发环境完成后, 支持自动构建, 自动刷新, sass语法 等功能

1、创建项目路径

```//cd 项目路径
​
mkdir react_test
​
// 使用 npm 初始化项目
cd react_test
npm init```

2、安装相关的依赖和软件包

```//这里主要示例安装 react react-dom react-scripts
npm install react react-dom react-scripts```

3、配置 package.json 文件和 webpack.config.js文件

## 组件

组件是 React 的核心,组件机制允许你将UI切分成独立、可复用的部分,并针对每个部分单独去做一定的处理。

#### 组件的好处

1、标记鲜明,容易维护,易与复用

2、块状化结构,减少css 的书写,并且方便扩展

## React 中的组件

### React 构建组件的两种方式

#### 构造函数构建组件

在React中,构造函数,就是一个最基本的组件,如果想要把组件放到页面中,可以把 构造函数的名称,当作组件的名称,以 HTML 标签形式引入页面中即可。

> 注意:React在解析所有的标签的时候,是以标签的首字母来区分的,如果标签的首字母是小写,那么就按照普通的 HTML 标签来解析,如果首字母是大写,则按照组件的形式去解析渲染

```// 结论:组件的首字母必须是大写
 function HelloMessage(props) {
 // 在组件中,如果想要使用外部传递过来的数据,必须,显示的在 构造函数参数列表中,定义 props 属性来接收;
 // 通过 props 得到的任何数据都是只读的,不能从新赋值
 props.name = '000'
 return(
 <div>
 <h1>这是在Hello组件中定义的元素 --- {props.name}</h1>
 </div>
 )
 }```

#### Class 关键字构建组件

```class HelloMessage extends React.Component {
  render() {
    return <h1>Hello World!</h1>;
  }
}
  • 区别
  1. 用构造函数创建出来的组件:专业的名字叫做“无状态组件”

  2. 用class关键字创建出来的组件:专业的名字叫做“有状态组件”

JSX 语法

JSX是一种 JavaScript 的语法扩展,是 React 官方推出的一套语法规范。他可以在 JavaScript 写 HTML 标签,JSX 这种语法,就是为了把HTML模板直接嵌入到JS代码里面,这样就做到了模板和组件关联,但是 JS 不支持这种包含 HTML 的语法,所以需要通过工具将 JSX 编译输出成 JS 代码才能使用。

npm i babel-preset-react -D
​```

> 1、如要要使用 JSX 语法,必须先运行 `cnpm i babel-preset-react -D`,然后再 `.babelrc` 中添加 语法配置;</br>  2、JSX语法的本质:还是以 React.createElement 的形式来实现的,并没有直接把 用户写的 HTML代码,渲染到页面上;</br>  3、 当 编译引擎,在编译JSX代码的时候,如果遇到了`<`那么就把它当作 HTML代码去编译,如果遇到了 `{}` 就把 花括号内部的代码当作 普通JS代码去编译;</br>  4、在JSX创建DOM的时候,所有的节点,必须有唯一的根元素进行包裹;

#### JSX 原理

JSX 其实就是 JavaScript 对象,JSX内部在运行的时候,也是先把 类似于HTML 这样的标签代码,  转换为了 React.createElement 的形式;也就是说:我们写了 JSX 这样的标签,也并不是直接把 我们的 HTML 标签渲染到页面上,而是先转换成 React.createElement 这样的JS代码,再渲染到页面中;

![image](https://upload-images.jianshu.io/upload_images/20519044-74e477ceea6121ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 

```import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
​
class Header extends Component {
 render () {
 return (
 <div>
 <h1 className='title'>React 学习</h1>
 </div>
 )
 }
}
​
ReactDOM.render(
 <Header />,
 document.getElementById('root')
)
​```

```import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
​
class Header extends Component {
 render () {
 return (
 React.createElement(
 "div",
 null,
 React.createElement(
 "h1",
 { className: 'title' },
 "React 学习"
 )
 )
 )
 }
}
​
ReactDOM.render(
 React.createElement(Header, null),
 document.getElementById('root')
);

组件嵌套

返回多个 JSX 元素必须要用一个外层的 JSX 元素把所有内容包裹起来。返回并列多个 JSX 元素是不合法的。

image

复用性非常强,我们可以把组件的内容封装好,然后灵活在使用在任何组件内。另外这里要注意的是,自定义的组件都必须要用大写字母开头,普通的 HTML 标签都用小写字母开头。

组件state

React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。 React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

​
class CollectButton extends React.Component{
 constructor(){
 super();
 this.state = {
 collect:false,
 collectPrompt:"未收藏"
 }
 }
​
 handleClick(){
 var status = !this.state.collect
 var text = status?"收藏":"未收藏";
 this.setState({
 collect:status,
 collectPrompt:text
 });
 }
​
 render(){
 return(
 <button onClick={()=>{
 this.handleClick()
 }}>{this.state.collectPrompt}</button>
 );
 }
}
​
export default CollectButton;```

## 组件通信

#### React Props

state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。这就是为什么有些容器组件需要定义 state 来更新和修改数据。 而子组件只能通过 props 来传递数据。

### 父传子

子组件定义接受数据属性名称  父组件向该属性赋值

```//父组件
class  Father extends React.Component {
  constructor() {
    super();
    this.state = {
      属性名称:属性值
    }
  }

  render(){
    return({
      <子组件 子组件属性名称={this.state.属性名称}/>
    });
  }
}

//子组件接受
class Son extends React.Component{
  constructor(props){
    super();
    this.state = props;
  }

  render(){
    return(
      <子元素标签>{this.state.子组件属性名称}</子元素标签>
    );
  }

}

子传父

回调函数的方式

class  Father extends React.Component {
  constructor() {
    super();
    this.state = {
      属性名称:属性值
    }
  }

  // 父组件接受数据定于函数
  getData = (需要传递给父组件的值)=>{
    //拿到子组件传递给父组件的值
  }

  render(){
    return({
      <子组件 子组件属性名称={this.state.属性名称} 父组件接受数据函数名称={this.getData}/>
    });
  }
}

//子组件接受
class Son extends React.Component{
  constructor(props){
    super();
    this.state = props;
  }

  handleClick(需要传递给父组件的值){
    this.props.父组件接受数据函数名称(需要传递给父组件的值)
  }

  render(){
    return(
      <子元素标签 onClick={()=>{
        this.handleClick(需要传递给父组件的值);
      }}>{this.state.子组件属性名称}</子元素标签>

    );
  }

}

兄弟组件

通过父组件进行数据交互

跨组件通信

数据类型校验

children

defaultProps

React 获取dom

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
​
class Index extends Component {
 onClick(event){
 console.log(event.target.value);
 // 第一种方式
 var submitObj = document.getElementById('submit');
 submitObj.style.color = 'green';
 // 第二种方式
 ReactDOM.findDOMNode(submitObj).style.color = 'yellow';
 // 第三种方式
 this.refs.submit.style.color = 'blue';
 }
 render(){
 return (
 <div>
 <input id='submit' ref='submit'
 type='button' value='style'
 onClick={this.onClick.bind(this)}/>
 </div>
 )
 }
}```
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351