React組件、組件封裝、組件通信

React

目標

  • 了解組件以及組件的封裝

  • 組件通信

  • children

  • defaultProps

React

React.js 是一個幫助你構建頁面 UI 的庫。React.js 將幫助我們將界面分成了各個獨立的小塊,每一個塊就是組件,這些組件之間可以組合、嵌套,就成了我們的頁面。

一個組件的顯示形態(tài)和行為有可能是由某些數據決定的。而數據是可能發(fā)生改變的,這時候組件的顯示形態(tài)就會發(fā)生相應的改變。而 React.js 也提供了一種非常高效的方式幫助我們做到了數據和組件顯示形態(tài)之間的同步。

React.js 不是一個框架,它只是一個庫。它只提供 UI (view)層面的解決方案。在實際的項目當中,它并不能解決我們所有的問題,需要結合其它的庫,例如 Redux、React-router 等來協(xié)助提供完整的解決方法。

  • 模塊化:從 代碼 的角度,去分析問題,把我們編程時候的業(yè)務邏輯,分割到不同的模塊中來進行開發(fā),這樣能夠方便代碼的重用;

  • 組件化:從 UI 的角度,去分析問題,把一個頁面,拆分為一些互不相干的小組件,隨著我們項目的開發(fā),我們手里的組件會越來越多,最后,我們如果要實現一個頁面,可能直接把現有的組件拿過來進行拼接,就能快速得到一個完整的頁面, 這樣方便了UI元素的重用;組件是元素的集合體。

vue 組件化與 React組件化

1、Vue是如何實現組件化的:.vue 組件模板文件,瀏覽器不識別這樣的.vue文件,所以,在運行前,會把 .vue 預先編譯成真正的組件;

  • template: UI結構

  • script: 業(yè)務邏輯和數據

  • style: UI的樣式

2、React如何實現組件化:在React中實現組件化的時候,根本沒有像 .vue 這樣的模板文件,而是,直接使用JS代碼的形式,去創(chuàng)建任何你想要的組件;

  • React中的組件,都是直接在 js 文件中定義的;

  • React的組件,并沒有把一個組件 拆分為 三部分(結構、樣式、業(yè)務邏輯),而是全部使用JS來實現一個組件的;(也就是說:結構、樣式、業(yè)務邏輯是混合在JS里面一起編寫出來的)

React中的核心概念

  • 虛擬DOM(Virtual Document Object Model)

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

  • DOM和虛擬DOM的區(qū)別:

    • DOM是由瀏覽器中的JS提供功能,所以我們只能人為的使用 瀏覽器提供的固定的API來操作DOM對象;

    • 虛擬DOM:并不是由瀏覽器提供的,而是我們程序員手動模擬實現的,類似于瀏覽器中的DOM,但是有著本質的區(qū)別;

  • 為什么要實現虛擬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,每當我們從前到后,把所有層的節(jié)點對比完后,必然能夠找到那些 需要被更新的元素;

*   component diff:在對比每一層的時候,組件之間的對比,叫做 component diff;當對比組件的時候,如果兩個組件的類型相同,則暫時認為這個組件不需要被更新,如果組件的類型不同,則立即將舊組件移除,新建一個組件,替換到被移除的位置;

*   element diff:在組件中,每個元素之間也要進行對比,那么,元素級別的對比,叫做 element diff;

*   key:key這個屬性,可以把 頁面上的 DOM節(jié)點 和 虛擬DOM中的對象,做一層關聯(lián)關系;

#### 配置和安裝 React

##### 使用 create-react-app 腳手架安裝 React 開發(fā)環(huán)境

用 React 官網提供的 create-react-app 來搭建非常簡單:

1、配置安裝 npm

```npm -v```

2、安裝 create-react-app

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

3、創(chuàng)建 React 項目

```//cd 創(chuàng)建項目的目錄
cd 項目路徑
?
//創(chuàng)建
create-react-app 項目名稱```

這條命令會幫我們構建一個叫 react_test 的工程,并且會自動地幫助我們安裝所需要的依賴,現在只需要安靜地等待它安裝完。

4、啟動工程開始項目

```//cd 到項目路徑
cd react_test
?
//npm 啟動工程
npm start```

##### 手動創(chuàng)建 React 開發(fā)環(huán)境

面對復雜的項目, 入門級的構建工具, 是遠遠不夠的, 我們這里從零開始, 用webpack, 手動配置一個獨立的React開發(fā)環(huán)境, 開發(fā)環(huán)境完成后, 支持自動構建, 自動刷新, sass語法 等功能

1、創(chuàng)建項目路徑

```//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在解析所有的標簽的時候,是以標簽的首字母來區(qū)分的,如果標簽的首字母是小寫,那么就按照普通的 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>;
  }
}
  • 區(qū)別
  1. 用構造函數創(chuàng)建出來的組件:專業(yè)的名字叫做“無狀態(tài)組件”

  2. 用class關鍵字創(chuàng)建出來的組件:專業(yè)的名字叫做“有狀態(tài)組件”

JSX 語法

JSX是一種 JavaScript 的語法擴展,是 React 官方推出的一套語法規(guī)范。他可以在 JavaScript 寫 HTML 標簽,JSX 這種語法,就是為了把HTML模板直接嵌入到JS代碼里面,這樣就做到了模板和組件關聯(lián),但是 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創(chuàng)建DOM的時候,所有的節(jié)點,必須有唯一的根元素進行包裹;

#### 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 把組件看成是一個狀態(tài)機(State Machines)。通過與用戶的交互,實現不同狀態(tài),然后渲染 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 主要的區(qū)別在于 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>
 )
 }
}```
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容