[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 擴展閱讀

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM