React

網頁總是一個鏈接着另一個的,React一大優勢在於每次鏈接到另一個頁面上去的時候,不需要向傳統頁面一樣,得銷燬所有代碼,重新渲染新頁面的代碼,而只在一個頁面上展現新的內容——單頁頁面

React另一個優勢是,以往的單頁頁面你需要考慮哪個元素要被刪除、哪個元素的行爲要被修改,而我們只需要告訴React我們想要的最終頁面的效果,React會自動幫我們處理頁面上的元素,做刪除、修改等操作。

而我只知道React有自己的虛擬DOM,它會對比虛擬DOM和真實DOM的差別,然後在適當的時機更新頁面。至於它怎麼對比的?怎麼知道差別的?怎麼進行修改的?我不知道,不過,對於我們,誰在乎呢?

必須首先知道的關於React的術語

  • JSX語法:React特有語法,用來搭建虛擬DOM
  • 組件(Component):一個個代碼塊,用來封裝各種功能,可以類比於函數(function
  • props&status:組件的所有靜態屬性 & 所有動態屬性

引入React

想要使用React,你需要先引入:

<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin</script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

上面兩個<script>引入了React的核心庫,最後一句<script>引入jsx語法編譯器,因爲瀏覽器不懂jsx只知道javascript,所以,引入編譯器轉換爲瀏覽器能懂的javascript語言

請參考React官方文檔以獲取最新版本React的引入:https://reactjs.org/docs/add-...

初步使用React

並沒有什麼特別的技巧,先看代碼,再做解釋:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React First Try</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
    <div id="container"></div>

    <script type="text/babel">
        var container = document.querySelector("#container");

        ReactDOM.render(
            <div>
                <p>Batman</p>
                <p>catwoman</p>
            </div>,
            container
        );
    </script>
</body>
</html>

解釋:

  • 首先引入了三個<script>
  • 新建一個元素<div id="container"></div>
  • 我們必須在一個<scripr type="text/babel">中使用React,請注意<script>type
  • 像一般的javascript語法一樣,我們先獲取頁面元素

    var container = document.querySelector("#container");
  • 修改虛擬DOM,並渲染真實DOM
    其中,ReactDOM.render();就是在渲染,其含義是將第一個參數渲染到第二個參數下。而第一個參數<div>...</div>就是新的虛擬DOM的內容,可更改爲我們想要的真實DOM結構。

    ReactDOM.render(
        <div>
            <p>Batman</p>
            <p>catwoman</p>
        </div>,
        container
    );
  • 效果、頁面結構

初用React
初用React_頁面結構

  • 我們看到,頁面中已經添加了包含兩個<p>元素的<div>React.render()函數的第一個參數只能是一個標籤,不能是並列的兩個標籤。不過一個標籤裏的子標籤可以隨便的添加,所以最好的方法就是,在外面添加一個<div></div>

使用組件(Component

上面的方法是直接將你想要的寫在React.render()裏,通常的做法是引用組件

  • 定義一個組件

    class 組件名 extends React.Component(
        //your code
    );
  • 組件裏可以添加很多功能,比如想要添加一個按鈕,你只需直接寫你想要的DOM結構,而不需要使用javascript語法:createElement()appendChild()

    class 組件名 extends React.Component(
        render(){
            return (<button>Batman</button>);
        }
    );
  • 在組件裏寫好你想要的東西,使用React.render()進行渲染

    React.render(
        <組件名/>,
        想要渲染的位置
    )
  • 完整代碼可以如下

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>React First Try</title>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    </head>
    <body>
        <div id="container"></div>
    
        <script type="text/babel">
            var container = document.querySelector("#container");
            
            class Myname extends React.Component{
                render(){
                    return (<button>Batman</button>);
                }
            };
    
            ReactDOM.render(
                <Myname/>,
                container
            );
        </script>
    </body>
    </html>
  • 效果、頁面結構

初用組件

初用組件_頁面結構

  • 我們看到,頁面上出現了我們想要的按鈕,頁面結構裏也成功添加了<button>標籤。注意!!!組件名首字母必須大寫!!!引用組件注意代碼<組件名/>,一個符號都不能錯的!!!

使用props

props用來獲取組件的靜態屬性,可以先看下面的一個小例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React First Try</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
    <div id="container"></div>

    <script type="text/babel">
        var container = document.querySelector("#container");

        class Myname extends React.Component{
            render(){
                return (<button type={this.props.buttontype}>{this.props.children}</button>);
            }
        };

        ReactDOM.render(
            <Myname buttontype="submit">Batman</Myname>
            ,
            container
        );
    </script>
</body>
</html>

不必驚慌,修改的地方只有組件的render()和實際渲染的render()兩個函數。

  • 第一個render()添加了<button>type屬性,該屬性值指向{this.props.buttontype},意思是該組件名爲buttontype的靜態屬性。這個render()還將<button>的顯示文字指向{this.props.children},意思是該組件的子元素這個靜態屬性
  • 第二個render()函數添加了<Myname>的靜態屬性buttontype,和一個text類型的子元素Batman
  • 結論就是:在渲染真實DOM的時候,會創建一個<button></button>標籤,它的type屬性值爲submit,文字顯示爲Batman
  • 效果、頁面結構,哈哈哈,沒啥區別,沒區別就對了:

使用props

react_props_頁面結構

props的傳遞性

props只能從父元素向下傳遞給子元素:
props_傳遞性

當有多個屬性你想傳遞的時候,你的代碼可能就會是這樣的,會重複很多遍{this.props.propsName}

<script>
class Me extends React.Component{
    render(){
        return (
            <div>
                <p>{this.props.props1}</p>
                <p>{this.props.props2}</p>
                <p>{this.props.props3}</p>
            </div>
        );
    }
};

class Father extends React.Component{
    render(){
        return (
            <Me props1={this.props.props1} props2={this.props.props2} props3={this.props.props3}/>
        );
    }
};

ReactDOM.render(
    <Father props1="a" props2="b" props3="c"/>,container
);
</script>

如果你不想重複很多遍繁瑣的{this.props.propsName},那你可以使用擴展運算符...表示取到所有的靜態屬性並且都使等於{this.props.propsName},所以我們的代碼可以稍作簡化:

<script>
class Me extends React.Component{
    render(){
        return (
            <div>
                <p>{this.props.props1}</p>
                <p>{this.props.props2}</p>
                <p>{this.props.props3}</p>
            </div>
        );
    }
};

class Father extends React.Component{
    render(){
        return (
            <Me {...props}/>      //👈👈使用擴展運算符進行簡化{...props}
        );
    }
};

ReactDOM.render(
    <Father props1="a" props2="b" props3="c"/>,container
);
</script>

React操作CSS

此方法可以使你在<script>裏更改、渲染CSS。不過使用ReactJSX語法會和CSS語法有一點點不同,就一點點┑( ̄Д  ̄)┍

因爲剛開始接觸,代碼不難,所以直接先看示例代碼吧;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>React First Try</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
    <div id="container"></div>

    <script type="text/babel">
        var container = document.querySelector("#container");

        class Mycss extends React.Component{
            render(){
                var letterColor = {
                    padding: 10,
                    margin: 10,
                    backgroundColor: this.props.thiscolor,
                    color: "#333",
                    display: "inline-block",
                    fontFamily: "monospace",
                    fontSize: 32,
                    textAlign: "center",
                };
                return (<div style={letterColor}>{this.props.children}</div>);
            }
        };

        ReactDOM.render(
            <div>
                <Mycss thiscolor="#58B3FF">B</Mycss>
                <Mycss thiscolor="#FF605F">a</Mycss>
                <Mycss thiscolor="#FFD52E">t</Mycss>
                <Mycss thiscolor="#49DD8E">m</Mycss>
                <Mycss thiscolor="#AE99FF">a</Mycss>
                <Mycss thiscolor="#FF6633">n</Mycss>
            </div>
            ,
            container
        );
    </script>
</body>
</html>
  • 哇!!代碼怎麼看上去又有這麼多的改動啊!!別慌張別慌張!其實和上一小節一樣,只改動了一些內容在組件的render()和真實渲染的render()兩個函數裏
  • 組件render()裏首先定義了一個虛擬CSS類,看上去符合CSS語法,但其實呢,他是一個JSX語法,仔細看,它就是一個用JSX語法寫的神似CSS對象。其中的一些區別如下:

    • 它不應該有pxpx這種東西JSX會自動補充
      react_css_沒有px
    • 它不應該有分號;來表示這個屬性結束了,請使用逗號,
      react_css_逗號
    • 它應該把除了純數字外的所有屬性值都加上引號""
      react_css_引號的使用
    • 它應該使用駝峯命名法來表示CSS使用連接號-的屬性名:backgroundColor
      react_css_駝峯命名法
  • 所以,在遵循了所有使用JSX語法描述CSS狀態的規則之後,你就可以成功的定義一個虛擬CSS。接着,在組件的render()裏調用它,像這樣<div style={letterColor}>style={虛擬CSS名}
  • 在這裏另一個知識點是,在定義虛擬CSSbackgroundColor時,它的參數值是一個變量this.props.thiscolor,同上一小節一樣,在真實渲染render()的第一個參數裏定義這個靜態變量<Mycss thiscolor="#58B3FF">。這樣,就成功在CSS(虛擬的)裏調用了其它地方的變量來確定屬性值。
  • 效果、頁面結構:值得注意的是,React處理的CSS是通過內聯方式(標籤中插入style屬性)實現的

react_css_效果
react_css_頁面結構

小結

這個時候,我們需要做一個小例子,來鞏固下關於組件CSS引入props的概念

我們想要實現的效果

我們想要實現的效果就是,當你輸入顏色代碼,上面就能正確的展示顏色:
調色板_效果

分離組件

React的世界,一切都是組件,頁面上所有的內容都是由一個個組件搭建起來的。你可以將結構劃分爲很小的組件,這樣實現的功能就很詳細。你也可以將結構劃分爲稍大的組件,功能就更集中。

所以,像我們這樣的小應用,下面的組件劃分方法就足以滿足要求:
調色板_組件劃分

編寫程序

在分析完結構需要分成多少組件之後,可以開始構造代碼~

  • 首先,我們編寫組件框架。其中每一個class就代表了我們分成的組件。在這裏class ColorName表示文字部分,class Color表示顏色顯示區,class Board表示用來承載這個應用的底板。每個組件都有一個render()函數用來之後渲染組件到DOM上。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Color</title>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    </head>
    <body>
        <div id="container"></div>
    
        <script type="text/babel">
            var container = document.querySelector("#container");
    
            class ColorName extends React.Component{
                render(){
                 
                }
            };
    
            class Color extends React.Component{
                render(){
    
                }
            };
    
            class Board extends React.Component{
                render(){
    
                }
            };
    
            ReactDOM.render(
                <Board/>,container
            );
        </script>
    </body>
    </html>
  • 上述步驟等於搭完了骨架,我們需要填充肌肉。寫下,最終需要每個組件分別返回什麼標籤:
    ColorName組件返回一個<p>標籤,用以展現顏色的色號
    Color組件返回一個<div>標籤,用來顯示顏色
    Board組件返回一個<div>標籤,並且把上兩個組件包在一起

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Color</title>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    </head>
    <body>
        <div id="container"></div>
    
        <script type="text/babel">
            var container = document.querySelector("#container");
    
            class ColorName extends React.Component{
                render(){
                    return (<p>{this.props.colorName}</p>);
                }
            };
    
            class Color extends React.Component{
                render(){
                    return (<div id="color"></div>);
                }
            };
    
            class Board extends React.Component{
                render(){
                    return (
                        <div>
                            <Color colorName = {this.props.colorName}/>
                            <ColorName colorName = {this.props.colorName}/>
                        </div>
                    );
                }
            };
    
            ReactDOM.render(
                <Board colorName="#f7a87d"/>,container
            );
        </script>
    </body>
    </html>
  • 接下來我們只需要添加你想要的CSS就OK了,不過在添加CSS之前,我想對上一步驟簡單解釋:我們在渲染真實DOM時定義了一個靜態屬性colorName="#f7a87d",經由組件Board傳入組件ColorNameColor。最後通過每個組件各自的render()函數的return渲染在頁面上。
  • 最後我們需要添加一些CSS幫頁面穿點衣服,其中對CSS的引入使用了兩種方法,使用React引入和引入外部CSS文件:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Color</title>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
        <style>
            #board{
                width: 300px;
                height: 400px;
                /* border: 1px solid red; */
                border-radius: 3%;
                box-shadow: 3px 5px 7px 1px rgba(128,128,128,1);
            }
    
            #color{
                height: 80%;
                border-radius: 3%;
                box-shadow: 1px 1px 6px 1px rgba(128,128,128,1);
            }
        </style>
    </head>
    <body>
        <div id="container"></div>
    
        <script type="text/babel">
            var container = document.querySelector("#container");
    
            class ColorName extends React.Component{
                render(){
                    var ColorNameStyle = {
                        fontSize: "2.5em",
                        fontFamily: "sans-serif",
                        fontWeight: "bold",
                        textAlign: "center",
                        margin: 17,
                    };
    
                    return (<p style={ColorNameStyle}>{this.props.colorName}</p>);
                }
            };
    
            class Color extends React.Component{
                render(){
                    var colorStyle = {
                        backgroundColor: this.props.colorName,
                    };
    
                    return (<div style={colorStyle} id="color"></div>);
                }
            };
    
            class Board extends React.Component{
                render(){
                    return (
                        <div id="board">
                            <Color colorName = {this.props.colorName}/>
                            <ColorName colorName = {this.props.colorName}/>
                        </div>
                    );
                }
            };
    
            ReactDOM.render(
                <Board colorName="#f7a87d"/>,container
            );
        </script>
    </body>
    </html>

使用state

以上的各個步驟可以創建一個基本的靜態頁面,如果想要創建一個有點動態,看上不是死氣沉沉的頁面,那就一定需要state。正如之前提到的,props包含了所有的靜態屬性,state則包含了所有用於動態展示的屬性。

這時,我們需要一個例子

我們的目標

react_state_效果

分離組件

外面一個黑的長方形邊框;內部一個黑色的底板;#5dffff的動態數字;三行文字

編寫代碼

  • 編寫代碼框架:Times類表示變化的數字;Words表示三行灰色的文字;BlackBoard表示黑色的底板;Board表示最外面一圈黑邊框

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Lightning</title>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    </head>
    <body>
        <div id="container"></div>
    
        <script type="text/babel">
            var container = document.querySelector("#container");
    
            class Times extends React.Component{
                render(){
                    return ();
                }
            };
    
            class Words extends React.Component{
                render(){
                    return ();
                }
            };
    
            class BlackBoard extends React.Component{
                render(){
                    return ();
                }
            };
    
            class Board extends React.Component{
                render(){
                    return ();
                }
            };
    
            ReactDOM.render(
                <Board/>
                ,container
            );
        </script>
    </body>
    </html>
  • 然後我們需要添上返回的內容,我們就只看React的內容

    <script type="text/babel">
        var container = document.querySelector("#container");
    
        class Times extends React.Component{
            render(){
                return (<h1>Strike Times</h1>);
            }
        };
    
        class Words extends React.Component{
            render(){
                return (
                    <div>
                        <p>lightning strike</p>
                        <p>worldwide</p>
                        <p>(since you loaded this outstanding)</p>
                    </div>
                );
            }
        };
    
        class BlackBoard extends React.Component{
            render(){
                return (
                    <div>
                        <Times/>
                        <Words/>
                    </div>
                );
            }
        };
    
        class Board extends React.Component{
            render(){
                return (
                    <div>
                        <BlackBoard/>
                    </div>
                );
            }
        };
    
        ReactDOM.render(
            <Board/>
            ,container
        );
    </script>

    react_state_1

  • Strike Times變成動態,我們只需改變Times類:

    • 首先需要定義state:必須在constructor內定義this.state={}

      constructor(props){
          super(props);
          this.state = {
              strike: 0,
          };
      }
    • 使用生命週期鉤子componentDidMount鉤子裏的內容會在頁面渲染完成後被調用.
      在本例中,頁面渲染完成後會調用一個計時器setInterval(),計時器中調用的函數請使用箭頭函數,這樣被調用的函數裏的this纔會被正確的指向當前類,其它調用方法會指向window

      componentDidMount() {
          setInterval(() => this.addNumber(),1000);
      }
    • 定義你想調用的函數
      注意!!!如果你想修改state中的值,請必須使用this.setState()來修改!!

      addNumber(){
          this.setState({
              strike: this.state.strike + 100,
          });
      }
    • 最後,設定返回值,顯示的內容爲state中的strike

      render(){
          return (<h1>{this.state.strike}</h1>);
      }

react_state_2

  • 加上點樣式

    <script type="text/babel">
        var container = document.querySelector("#container");
    
        class Times extends React.Component{
           constructor(props){
               super(props);
               this.state = {
                   strike: 0,
               };
           }
    
            componentDidMount() {
                setInterval(() => this.addNumber(),1000);
            }
    
            addNumber(){
                this.setState({
                    strike: this.state.strike + 100,
                });
            }
    
            render(){
                var strikeStyle = {
                    margin: 0,
                    padding: "55px",
                    color: "#5dffff",
                    fontSize: "60px",
                }
            
                return (<h1 style={strikeStyle}>{this.state.strike}</h1>);
            }
        };
    
        class Words extends React.Component{
            render(){
                var words = {
                    fontFamily: "sans-serif",
                    margin: 0,
                    padding: 0,
                };
                var wordStyle = {
                    wordNormal: {
                        ...words,
                        color: "#999999",
                        fontSize: 33,
                    },
                    wordBig: {
                        ...words,
                        color: "#999999",
                        fontSize: 50,
                    },
                    wordSmall: {
                        ...words,
                        color: "#4d4d4d",
                    },
                }
    
                return (
                    <div>
                        <p style = {wordStyle.wordNormal}>lightning strike</p>
                        <p style = {wordStyle.wordBig}>worldwide</p>
                        <p style = {wordStyle.wordSmall}>(since you loaded this outstanding)</p>
                    </div>
                );
            }
        };
    
        class BlackBoard extends React.Component{
            render(){
                return (
                    <div style = {this.props.style}>
                        <Times/>
                        <Words/>
                    </div>
                );
            }
        };
    
        class Board extends React.Component{
            render(){
                var boardStyle = {
                    board: {
                        width: 300,
                        height: 400,
                        padding: 13,
                        backgroundColor: "white",
                        border: "2px solid black",
                    },
                    blackboard: {
                        height: "100%",
                        backgroundColor: "black",
                        borderRadius: "7%",
                        textAlign: "center",
                        lineHeight: "50px",
                    }
                };
    
                return (
                    <div style={boardStyle.board}>
                        <BlackBoard style = {boardStyle.blackboard}/>
                    </div>
                );
            }
        };
    
        ReactDOM.render(
            <Board/>
            ,container
        );
    </script>

react_state_結果

使用JSX

即使我們在之前的文章中已經開始使用了JSX這種React特別的語法,但是,我們還是應該爲它專門開闢一個新的章節,因爲,JSX組件組件生命週期React的三大奠基核心(哈哈哈,當然是我的個人見解)。

說到JSX,令人印象深刻的就是各種在js裏添加html標籤和出現在各個地方的{}

js裏添加html標籤

在提倡 css樣式js行爲html標籤 分離的時代,這樣的設計別出心裁。主要是因爲React的基礎設施不是傳統的html標籤,而是各個組件。一個組件裏包含了構成頁面某一部分所需要的所有的 css樣式js行爲html標籤 。 所以,遵循這樣的思路,在js裏添加html標籤沒什麼稀奇的。

像這樣:

var myname = <h1>Batman</h1>;
function functionName(){
    // your codes
    return <h1>Batman</h1>;
}
const me = (
  <div>
    <h1>Batman</h1>
    <h2>hello gotham</h2>
  </div>
);

注意!!!JSX不能夠將 多個html標籤 直接賦給一個變量或者直接返回,需要將 多個html標籤 包括在一個父元素中,就像上例第三個例子一樣。

{}

js裏添加html標籤對我們來說已經見怪不怪了,大括號{}的使用纔是精髓。哈哈哈~~

{}用於在React中的各個地方引用各種合理的JS表達式(valid JavaScript expression)。大括號裏可以是變量user.username、表達式2+2、函數調用functionName(user)等。

像這樣:

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
const element = <img src={user.avatarUrl}></img>;
const element = <h1>2+2={2+2}</h1>;
function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);

ReactDOM.render(
  element,
  document.getElementById('root')
);

另外,還有雙括號{{}}的寫法,這種表達方式用於在JSX裏內聯樣式。

{{}}內的內容:

  • 對象的寫法,將css裏的;變成,
  • 屬性名使用駝峯寫法,css裏-後面的第一個字母大寫
  • 只會生效最後一個style,下例中只會生效style={gothamStyle}

    var myName = <h1 style={{color:"black"}} style={{fontSize:"25px"}} style={gothamStyle}>Batman</h1>;

像這樣:

const myName = <h1 style={{color:"black",fontSize:"25px"}}>Batman</h1>;

關於更多React中操作CSS,你還可以瀏覽這篇文章:https://www.jianshu.com/p/850...

JSX的優勢

  • 防止XSS (cross-site-scripting)攻擊。因爲所有內容在被React渲染到頁面上前都會先轉成字符串
  • 小巧靈活。JSX本質就是Javascript,所以,JSX可以被放在任何一個地方。再加上JSX裏的內容非常豐富。結合React的設計思想,JSX非常好用。
  • 當然JSX還可以撰寫css內容,詳細可以參見之前章節:React操作CSS

使用JSX的一個例子

只要使用React搭建網站必然需要用到JSX,額,雖然官方是這樣表示的:
jsx使用與否
Well~我們還是快速的過一遍這個例子

我們要實現的目標

幾個圓圈過1秒就變顏色,顏色隨機從顏色庫裏選取
jsx例子效果圖

完整代碼

其實很簡單,Circle組件負責改變顏色的行爲,CreateCircle組件負責定義樣式並渲染這些圓圈。

然後因爲一直是動態的,所以,使用Circle組件的state,每個一段時間setInterval都會調用changeColor函數,來改變state裏的內容,改變之後React會重新渲染頁面被改動的部分。

值得注意的是,在這個例子中,JSX被運用在任何一個位置,

  • 可以被壓到數組中去

    colorarray.push(<CreateCircle bgColor={colors[random]} key={i}/>)
  • 被渲染

    render(){
        return (<div>{this.state.colorArray}</div>);
    };
  • 撰寫、引用css

    class CreateCircle extends React.Component{
        render(){
            var circleStyle = {
                padding: 10,
                margin: 20,
                display: "inline-block",
                backgroundColor: this.props.bgColor,
                borderRadius: "50%",
                width: 100,
                height: 100,
            };
    
            return (<div style={circleStyle}></div>);
        }
    };

注意!!!在React中使用key={}屬性來唯一標識一個組件<CreateCircle key={i}/>

完整代碼:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Lightning</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>

<body>
    <div id="container"></div>

    <script type="text/babel">
        var container = document.getElementById("container");
        var colors = ["#393E41","#E94F37","#1C89BF","#A1D363","#85FFC7","#297373","#FF8552","#A40E4C"];

        class Circle extends React.Component{
            constructor(props){
                super(props);
                this.state = {
                    colorArray: [],
                };
            };

            changeColor(){
                var colorarray = [];
                this.setState({
                    colorArray: [],
                });
                for(var i=0;i < colors.length;i++){
                    var random = Math.floor(Math.random()*colors.length);
                    colorarray.push(<CreateCircle bgColor={colors[random]} key={i}/>)
                    this.setState({
                        colorArray: colorarray,
                    });
                }
            };

            componentDidMount(){
                setInterval(() => this.changeColor(),1000);
            };

            render(){
                return (<div>{this.state.colorArray}</div>);
            };
        };

        class CreateCircle extends React.Component{
            render(){
                var circleStyle = {
                    padding: 10,
                    margin: 20,
                    display: "inline-block",
                    backgroundColor: this.props.bgColor,
                    borderRadius: "50%",
                    width: 100,
                    height: 100,
                };

                return (<div style={circleStyle}></div>);
            }
        };
        
        ReactDOM.render(
            <Circle/>
            ,container
        )
        
    </script>
</body>

</html>

React中的事件

事件的意義不用多說,事件是頁面與用戶交互的唯一途徑,人機交互大部分還是通過鼠標和鍵盤吧,當然還有像手寫板、麥克風、攝像頭等設備,但截至今日前端貌似沒有什麼權限,不然安全性就太差了。

React中,事件的綁定大致和原生網頁相似,大概也就是命名方式不同this的指向不同這兩點區別。

可以參考:https://reactjs.org/docs/hand...

React中綁定事件

  • 直接綁定

    class Button extends React.Component{
        render(){
            return (<button onClick="console.log('Hello gotham')">Click me!</button>)
        }
    }

    WHAT??這不是和原生的一模一樣嗎?是呀,只是在命名上採用的是React喜愛的駝峯Camel-Case命名法,原生的都是小寫。但這種方法多老式。

  • 間接綁定

    class Button extends React.Component{
        consoleLog(){
            console.log("Hello gotham");
        }
    
        render(){
            return (<button onClick={this.consoleLog}>Click me!</button>)
        }
    }

    將函數拿到外面去,然後在元素的事件上綁定這個函數,綁定的時候使用JSX{}並且一定加上this,表示綁定的是這個組件裏的函數。

  • 超級間接綁定

    class Inner extends React.Component{
        render(){
            return (<button onClick={this.props.clickHandler}>Click me!</button>)
        }
    }
    
    class Outer extends React.Component{
        consoleLog(){
            console.log("Hello gotham");
        }
    
        render(){
            return (<Inner clickHandler={this.consoleLog}/>)
        }
    }

    哈哈哈,這是什麼鬼?就是利用了Reactprops,把函數綁定在一個props上,本例中是clickHandler,然後渲染了新組件,在新組件中,可以使用this.props來調用這個函數。簡單來說就是,將函數從父組件通過props傳遞到了子組件

this的指向

React中,絕大部分的this都指向組件本身。但是,在自定義的函數中,this是沒有指向的,所以會有this is undefined的報錯,尤其是自定義的函數需要引用函數外組件內的其它資源的時候。
沒有綁定this的報錯

像下面這樣寫是會報錯的:
我們想要點擊Hello gotham按鈕調用greeting函數,greeting函數會調用gotham函數打印Hello gotham字樣。但是,greeting函數裏的this沒有指向,所以會出現上面的報錯。

class Welcome extends React.Component{
    gotham(){
        console.log("Hello gotham");
    }    

    greeting(){
        this.gotham();
    }

    render(){
        return (<button onClick={this.greeting}>Hello gotham<button/>)
    }
}

所以,如果想要在自定義函數中調用同組件其它資源,你有下面3中方法來綁定this

  • constructor中綁定

    class Welcome extends React.Component{
        constructor(props){
            super(props);
            this.greeting = this.greeting.bind(this);    👈這句是綁定
        }
    
        gotham(){
            console.log("Hello gotham");
        }    
    
        greeting(){
            this.gotham();
        }
    
        render(){
            return (<button onClick={this.greeting}>Hello gotham<button/>)
        }
    }
  • 內聯式綁定

    class Welcome extends React.Component{
        gotham(){
            console.log("Hello gotham");
        }    
    
        greeting(){
            this.gotham();
        }
    
        render(){
                                                  👇👇👇👇👇👇這裏是綁定
            return (<button onClick={this.greeting.bind(this)}>Hello gotham<button/>)
        }
    }
  • 內聯式箭頭函數綁定

    class Welcome extends React.Component{
        gotham(){
            console.log("Hello gotham");
        }    
    
        greeting(){
            this.gotham();
        }
    
        render(){
                                     👇👇👇👇👇👇👇👇👇👇👇👇這裏是綁定
            return (<button onClick={(e) => this.greeting(e)}>Hello gotham<button/>)
        }
    }

關於綁定this還可以參考:https://www.jianshu.com/p/95a...

合成事件SyntheticEvent

React中的合成事件可以對應爲通常函數中的事件對象event

function gotham(event){
    // your codes
}

e...這個功能有點多,你可以自己打印出來看看呀,或者看看官方文檔:https://reactjs.org/docs/even...

這裏只貼出來關於鼠標和鍵盤事件:

  • 鼠標事件

    boolean   altKey
    boolean   ctrlKey
    boolean   shiftKey
    boolean   metaKey
    number    button
    number    buttons
    number    clientX
    number    clientY
    boolean   getModifierState(key)
    number    pageX
    number    pageY
    DOMEventTarget   relatedTarget
    number    screenX
    number    screenY

    適用於如下事件:

    onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp
  • 鍵盤事件

    boolean  altKey
    number   charCode
    boolean  ctrlKey
    boolean  getModifierState(key)
    string   key
    number   keyCode
    string   locale
    number   location
    boolean  metaKey
    boolean  repeat
    boolean  shiftKey
    number   which

    適用於如下事件:

    onKeyDown onKeyPress onKeyUp

關於事件的小例子

我們的目標

點擊加號按鈕數字加1,按住shift點擊加號,數字加10
React事件例子

實現思路

  • 分割組件。底板、數字、按鈕
  • 點擊按鈕數字變化,所以,將資料存放於數字組件,並且通過數字組件調用按鈕
  • 鍵盤事件的合成事件中,能夠監聽shift鍵是否被按下

拋開樣式的完整代碼

其它的無關緊要,注意Show組件內的increase函數,我們可以看到合成事件e.shiftKey{this.increase.bind(this)}的使用

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>react-event</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>

<body>
    <div id="container"></div>

    <script type="text/babel">
        var container = document.querySelector("#container");

        class Button extends React.Component{
            render(){
                return (<button onClick={this.props.clickHandler}>+</button>)
            }
        }

        class Show extends React.Component{
            constructor(props){
                super(props);
                this.state = {
                    number: 0,
                };
            }

            increase(e){
                var num = this.state.number;
                if(e.shiftKey){
                    num += 10;
                }else{
                    num += 1;
                }
                this.setState({
                    number: num,
                });
            }

            render(){
                return (
                    <div>
                        <p>{this.state.number}</p>
                        <Button clickHandler={this.increase.bind(this)}/>
                    </div>
                )
            }
        }

        class Board extends React.Component{
            render(){
                return (
                    <div>
                        <Show/>
                    </div>
                );
            }
        };

        ReactDOM.render(
            <Board/>,
            container
        )
    </script>
</body>

</html>

組件的生命週期Lifecycle

React創造出來組件,同時也給組件配上了生命週期,用來更好的控制組件,這也是React的一大優勢。

組建的生命週期可以參考這個:https://reactjs.org/docs/reac...。往下多翻翻~~
這個參考資料也非常棒:https://www.w3cplus.com/react...

常用生命週期

  • componentDidMount()
  • componentDidUpdate()
  • componentWillUnmount()

不常用且慎用的生命週期

  • shouldComponentUpdate()
  • static getDerivedStateFromProps()
  • getSnapshotBeforeUpdate()
  • static getDerivedStateFromError()
  • componentDidCatch()

消失的生命週期

消失的生命週期不理他。

React Router

官方文檔:https://reacttraining.com/rea...
github:https://github.com/ReactTrain...

React Router就把他看作是一個插件吧,中文名:React路由

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章