react 學習筆記

Babel 轉譯器 這是react自帶的一個編譯器javascript

props和states一個是組件外部的,一個是組件內部的css

 

組件 & Props

組件能夠將UI切分紅一些的獨立的、可複用的部件,這樣你就只需專一於構建每個單獨的部件。html

組件從概念上看就像是函數,它能夠接收任意的輸入值(稱之爲「props」),並返回一個須要在頁面上展現的React元素。java

函數定義/類定義組件

定義一個組件最簡單的方式是使用JavaScript函數:react

function Welcome(props) { return <h1>Hello, {props.name}</h1>; } 

該函數是一個有效的React組件,它接收一個單一的「props」對象並返回了一個React元素。咱們之因此稱這種類型的組件爲函數定義組件,是由於從字面上來看,它就是一個JavaScript函數。git

你也可使用 ES6 class 來定義一個組件:github

class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } } 

上面兩個組件在React中是相同的。api

咱們將在下一節討論類的一些額外特性。在那以前,咱們都將使用較爲簡潔的函數定義組件。網絡

組件渲染

在前面,咱們遇到的React元素都只是DOM標籤:app

const element = <div />; 

然而,React元素也能夠是用戶自定義的組件:

const element = <Welcome name="Sara" />; 

當React遇到的元素是用戶自定義的組件,它會將JSX屬性做爲單個對象傳遞給該組件,這個對象稱之爲「props」。

例如,這段代碼會在頁面上渲染出」Hello,Sara」:

function Welcome(props) { return <h1>Hello, {props.name}</h1>; } const element = <Welcome name="Sara" />; ReactDOM.render( element, document.getElementById('root') ); 

在 CodePen 上試試。

咱們來回顧一下在這個例子中發生了什麼:

  1. 咱們對<Welcome name="Sara" />元素調用了ReactDOM.render()方法。
  2. React將{name: 'Sara'}做爲props傳入並調用Welcome組件。
  3. Welcome組件將<h1>Hello, Sara</h1>元素做爲結果返回。
  4. React DOM將DOM更新爲<h1>Hello, Sara</h1>

警告:

組件名稱必須以大寫字母開頭。

例如,<div /> 表示一個DOM標籤,但 <Welcome /> 表示一個組件,而且在使用該組件時你必須定義或引入它。

組合組件

組件能夠在它的輸出中引用其它組件,這就可讓咱們用同一組件來抽象出任意層次的細節。在React應用中,按鈕、表單、對話框、整個屏幕的內容等,這些一般都被表示爲組件。

例如,咱們能夠建立一個App組件,用來屢次渲染Welcome組件:

function Welcome(props) { return <h1>Hello, {props.name}</h1>; } function App() { return ( <div>  <Welcome name="Sara" />  <Welcome name="Cahal" />  <Welcome name="Edite" /> </div> ); } ReactDOM.render( <App />, document.getElementById('root') ); 

在 CodePen 上試試。

一般,一個新的React應用程序的頂部是一個App組件。可是,若是要將React集成到現有應用程序中,則能夠從下而上使用像Button這樣的小組件做爲開始,並逐漸運用到視圖層的頂部。

警告:

組件的返回值只能有一個根元素。這也是咱們要用一個<div>來包裹全部<Welcome />元素的緣由。

提取組件

你能夠將組件切分爲更小的組件,這沒什麼好擔憂的。

例如,來看看這個Comment組件:

function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <img className="Avatar" src={props.author.avatarUrl} alt={props.author.name} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } 

在 CodePen 上試試。

這個組件接收author(對象)、text(字符串)、以及date(Date對象)做爲props,用來描述一個社交媒體網站上的評論。

這個組件因爲嵌套,變得難以被修改,可複用的部分也難以被複用。因此讓咱們從這個組件中提取出一些小組件。

首先,咱們來提取Avatar組件:

function Avatar(props) { return (  <img className="Avatar"  src={props.user.avatarUrl}  alt={props.user.name}  /> ); } 

Avatar做爲Comment的內部組件,不須要知道是否被渲染。所以咱們將author改成一個更通用的名字user

咱們建議從組件自身的角度來命名props,而不是根據使用組件的上下文命名。

如今咱們能夠對Comment組件作一些小小的調整:

function Comment(props) { return ( <div className="Comment"> <div className="UserInfo">  <Avatar user={props.author} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } 

接下里,咱們要提取一個UserInfo組件,用來渲染Avatar旁邊的用戶名:

function UserInfo(props) { return (  <div className="UserInfo">  <Avatar user={props.user} />  <div className="UserInfo-name">  {props.user.name}  </div>  </div> ); } 

這可讓咱們進一步簡化Comment組件:

function Comment(props) { return ( <div className="Comment">  <UserInfo user={props.author} /> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } 

在 CodePen 上試試。

提取組件一開始看起來像是一項單調乏味的工做,可是在大型應用中,構建可複用的組件徹底是值得的。當你的UI中有一部分重複使用了好幾回(好比,ButtonPanelAvatar),或者其自身就足夠複雜(好比,AppFeedStoryComment),相似這些都是抽象成一個可複用組件的絕佳選擇,這也是一個比較好的作法。

Props的只讀性

不管是使用函數或是類來聲明一個組件,它決不能修改它本身的props。來看這個sum函數:

function sum(a, b) { return a + b; } 

相似於上面的這種函數稱爲「純函數」,它沒有改變它本身的輸入值,當傳入的值相同時,老是會返回相同的結果。

與之相對的是非純函數,它會改變它自身的輸入值:

function withdraw(account, amount) { account.total -= amount; } 

React是很是靈活的,但它也有一個嚴格的規則:

全部的React組件必須像純函數那樣使用它們的props。

固然,應用的界面是隨時間動態變化的,咱們將在下一節介紹一種稱爲「state」的新概念,State能夠在不違反上述規則的狀況下,根據用戶操做、網絡響應、或者其餘狀態變化,使組件動態的響應並改變組件的輸出。

 

this.props.children

this.props 對象的屬性與組件的屬性一一對應,可是有一個例外,就是 this.props.children 屬性。它表示組件的全部子節點(查看 demo05)。

var NotesList = React.createClass({ render: function() { return ( <ol> { React.Children.map(this.props.children, function (child) { return <li>{child}</li>; }) } </ol> ); } }); ReactDOM.render( <NotesList> <span>hello</span> <span>world</span> </NotesList>, document.body ); 

上面代碼的 NoteList 組件有兩個 span 子節點,它們均可以經過 this.props.children 讀取,運行結果以下。

這裏須要注意, this.props.children 的值有三種可能:若是當前組件沒有子節點,它就是 undefined ;若是有一個子節點,數據類型是 object ;若是有多個子節點,數據類型就是 array 。因此,處理 this.props.children 的時候要當心。

React 提供一個工具方法 React.Children 來處理 this.props.children 。咱們能夠用 React.Children.map 來遍歷子節點,而不用擔憂 this.props.children 的數據類型是 undefined 仍是 object。更多的 React.Children 的方法,請參考官方文檔

jsx表明objects.

Hello.js

import React from 'react';

export default ({ name }) => <h1>Hello {name}!</h1>;
index.html
<div id="root"></div>
 index.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
import Name from './Name';
class App extends Component {
    constructor() {
        super();
        this.state = {
            name: 'React1',
            insertName: 'xss',
            hasNameFlag: true
        };
        console.log("indexconstructor");
    }

    changeName = () => {
        this.setState({
            insertName: 'yys',
        })
    }
    deleteName = () => {
        this.setState({
            hasNameFlag: false
        })

    }
    compomentwillMount() {
        console.log("indexcompomentwillMount");//dom放進去以前,只執行一次
    }

    componentDidMount() {
        console.log("indexcomponentDidMount");//dom放進去以後,只執行一次
    }
    componentWillReceiveProps(nextProps) {//有改變就執行,修改states的時候用到

        console.log("indexcomponentWillReceiveProps");
    }
    componentwillupDate() {//dom更新以前 
        console.log("indexcomponentwillupDate");
    }
    componentDidUpdate() {
        console.log("indexcomponentDidUpdate");//dom更新以後
    }

    componentWillUnmount() {
        console.log("indexcomponentWillUnmount");// dom組件被移除以前被調用,能夠用於作一些清理工做

    }
    render() {
        console.log("indexrender");
        const { insertName, hasNameFlag } = this.state;
        const a = (
            <h1 className={"greeting"} title="yys">
                Hello, world!
      </h1>
        );
        let name = null;
        if (hasNameFlag) {
            name = <Name name={insertName} >

                <span>world</span></Name>;
        }
        return (
            <div>
                <Hello name={this.state.name} />
                {name}
                <button onClick={this.changeName}>更名</button>
                <button onClick={this.deleteName}>刪除</button>
                <p>
                    Start editing to see some magic happen :)
        </p>
            </div>
        );
    }
}

render(<App />, document.getElementById('root'));

 

Name.js

import React, { Component } from 'react';
class Name extends Component {
    constructor(props) {
        super(props);
        this.state = {
            name: props.name
        };
        // console.log(this)
        console.log("constructor");
    }
    compomentwillMount() {
        console.log("compomentwillMount");
    }

    componentDidMount() {
        console.log("componentDidMount");
    }
    componentWillReceiveProps(nextProps) {
        if (nextProps.name === this.props.name) return;
        this.setState({
            name: nextProps.name
        })
        console.log("componentWillReceiveProps");
    }
    componentwillupDate() {
        console.log("componentwillupDate");
    }
    componentDidUpdate() {
        console.log("componentDidUpdate");
    }

    componentWillUnmount() {
        console.log("componentWillUnmount");

    }
    render() {
        console.log("render");
        const { name } = this.state;
        return <h2>{name}</h2>;
    }
}

export default Name;

 第一次刷新進入時:

點擊修改時

 

點擊刪除時:

 

 

constructor  1 只執行一次

compomentwillMount  1 dom放進去以前,也是隻執行一次

componentDidMount 1 dom放進去以後,也是隻執行一次

componentwillReceIveProps  有改變就執行,修改states的時候用到

componentwillupDate dom更新以前 

componentDidupDate  dom更新以後

componentWillUnmount  dom組件被移除以前被調用,能夠用於作一些清理工做
 

OK. so here goes. If you have a simple structure with a parent and 2 children like this:

<Parent> <Child/> <Child/> </Parent>

Then the sequence of events firing will be:

  1. <Parent> componentWillMount()
  2. <Parent> render(), which starts to render children
  3. <Child> componentWillMount() of the first child
  4. <Child> render() of the first child
  5. <Child> componentWillMount() of the second child
  6. <Child> render() of the second child
  7. <Child> componentDidMount() of the first child (these will start only after the last render in the tree has run)
  8. <Child> componentDidMount() of the second child
  9. <Parent> componentDidMount() (this one will run only after its last child has run componentDidMount)
相關文章
相關標籤/搜索