Props


就是組件屬性,在初始設定,建立後不變動


回想一下 React Element


React.createElement(type, [props], [...children])


我們用 code 來看一下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>My Component</title>
        <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
        <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
        <script>
            //設計組件類別
            class MyHead extends React.Component
            {
                render(){
                    return React.createElement("H" + this.props.level, null, "Hello World");
                }
            }


            window.addEventListener("load", ()=>{
                //1. 建立自訂的React組件實體
                let myHead = React.createElement(MyHead, {level:1});

                //2. 將建立好的React組件實體畫到容器中
                ReactDOM.render(myHead, document.body);
            })
        </script>
    </head>
</html>


React.createElement 的第二個參數我們傳入 {level:1} 的物件,然後在 class 中使用 this.props 取得外部傳入的屬性(也就是 this.props.level )


使用 Props 來實作巢狀結構

回到剛剛的定義

React.createElement(type, [props], [...children])

第三個參數是 子元件

想像我們要製作一個如下圖一樣的架構,我們會需要 MyHeadList 以及 MyHead 兩種 class:



我們直接看 code

class MyHead extends React.Component
{
    render(){
        return React.createElement("H" + this.props.level, null, "Hello World");
    }
}

class MyHeadList extends React.Component{
    render(){
        let heads = [];
        let head;
        for(let i = 0; i<6;i++){
            head = React.createElement(MyHead, {level:(i + 1)});
            heads.push(head);
        }
        return React.createElement("div", null, heads);
    }
}

放到剛剛的 Sample 後變成:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>My Component</title>
        <script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
        <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
        <script>
            //設計組件類別
            class MyHead extends React.Component
            {
                render(){
                    return React.createElement("H" + this.props.level, null, "Hello World");
                }
            }
            class MyHeadList extends React.Component{
                render(){
                    let heads = [];
                    let head;
                    for(let i = 0; i<6;i++){
                        head = React.createElement(MyHead, {level:(i + 1)});
                        heads.push(head);
                    }
                    return React.createElement("div", null, heads);
                }
            }


            window.addEventListener("load", ()=>{
                //1. 建立自訂的React組件實體
                let myHeadList = React.createElement(MyHeadList, null);

                //2. 將建立好的React組件實體畫到容器中
                ReactDOM.render(myHeadList, document.body);
            })
        </script>
    </head>
</html>

如果用 F12 打開 Chrome 的 DevTools,會看到其實上面的 code 跑出:

<body>
    <div>
        <h1>Hello World</h1>
        <h2>Hello World</h2>
        <h3>Hello World</h3>
        <h4>Hello World</h4>
        <h5>Hello World</h5>
    </div>
</body>



State


就是組件狀態,預期未來會變動的設定


先回過頭看一下剛剛省略的 React component constructor

在寫 constructor 的時候,必定要有一個 props 的參數, 參數必須傳遞給母元件

constructor(props){
    super(props);
}


接著看看 State 的 code

class MyHeadList extends React.Component{
    constructor(props){
        super(props);
        this.state={maxLevel:3};
        window.setTimeout(()=>{
            //this.setState({maxLevel:6});
            this.setState((currentState, currentProps)=>({maxLevel: currentState.maxLevel + 1}));
        }, 2000);
    }
    render(){
        let heads = [];
        let head;
        for(let i = 0; i<this.state.maxLevel;i++){
            head = React.createElement(MyHead, {level:(i + 1)});
            heads.push(head);
        }
        return React.createElement("div", null, heads);
    }
}


在預設的狀態下, this.state 為空白物件

在這個範例中

我們在 constructor 中指派物件 {maxLevel:3}this.state

由於 State 的定義中有說 *預期未來會變動的設定*,我們也要知道如變動 this.state

使 state 變動時,我們會使用 setState 的 method 變動 state

** 且記,變動不可以直接用 this.state=newState ,否則有可能導致狀態樹的錯亂問題…

setState 可以直接傳入新的物件,

    this.setState({maxLevel:6});

或是使用函式

    this.setState((currentState, currentProps)=>({maxLevel: currentState.maxLevel + 1}));
    
    或

    this.setState((currentState, currentProps)=>{
        return {maxLevel: currentState.maxLevel + 1}
    });


setState 之後,會自動呼叫 render 重繪畫面,不用自行呼叫


小結

回顧上面我們知道 React Component 中的 props 以及 state ,且多了解 React Component 的 constructor,並使用這些特性,完成一個巢狀的Sample。


Refernece