React筆記:元件(3)

libingql發表於2019-01-16

1. 元件定義

  元件是React的核心概念,元件將應用的UI拆分成獨立的、可複用的模組。

  定義元件的兩種方式:

  (1)類元件:使用ES6 class

  (2)函式元件:使用函式

  使用class定義元件的兩個條件:

  (1)class繼承自React.Component

  (2)class內部必須定義render(),render()返回代表該元件UI的React元素。

1.1 基本元件

  HelloWorld.js:

import React, { Component } from "react"

class HelloWorld extends Component {
    render() {
        return ( 
            <h1>Hello World!</h1>
        );
    }
}

export default HelloWorld;

  Index.js:

import React from 'react';
import ReactDOM from 'react-dom';

import HelloWorld from './components/HelloWorld'

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

  說明:ReactDOM.render()需要先匯入react-dom庫,這個庫會完成元件所代表的虛擬DOM節點到瀏覽器的DOM節點的轉換。

     使用export default預設匯出元件。

     default表示可以在別的檔案中使用import HelloWorld from './components/HelloWorld'匯入這個模組;

     如果沒有default,則需要使用import { HelloWorld } from './components/HelloWorld'來匯入模組。

1.2 元件的props

  元件props用於把父元件中的資料或方法傳遞給子元件。

  props是一個簡單結構的物件,它包含的屬性是由元件作為JSX標籤所使用的屬性組成。

  示例(1):

import React, { Component } from "react"

class HelloWorld extends Component {
    render() {
        return ( 
            <h1>Hello { this.props.name }!</h1>
        );
    }
}

export default HelloWorld;
import React from 'react';
import ReactDOM from 'react-dom';

import HelloWorld from './components/HelloWorld'

ReactDOM.render(<HelloWorld name={ 'Libing' } />, document.getElementById('root'));

  示例(2):

  TodoItem.js

import React, { Component } from 'react';

class TodoItem extends React.Component {
    render() {
        const { id, title } = this.props;
        
        return (
            <li>{ id }-{ title }</li>
        );
    }
}

export default TodoItem;

  TodoList.js

import React, { Component } from 'react';

import TodoItem from './TodoItem';

const data = [
    { id: 1, title: 'ToDo' },
    { id: 2, title: 'In Progress' },
    { id: 3, title: 'Done' }
]

class TodoList extends Component {
    render() {
        return ( 
            <ul>
            {
                data.map((item) =>
                    <TodoItem
                        id={ item.id }
                        title={ item.title }
                    />
                )
            } 
            </ul>
        );
    }
}

export default TodoList;

  index.js

import React from 'react';
import ReactDOM from 'react-dom';

import TodoList from './components/TodoList'

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

1.3 元件的state

  元件的state是元件內部的姿態,state的變化最終將反映在元件UI的變化。

  在元件的構造方法constructor中通過this.state定義元件的初始狀態,並通過呼叫this.setState()改變元件狀態,進而元件UI會隨之重新渲染。

  修改TodoItem.js

import React, { Component } from 'react';

class TodoItem extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            count: 0
        };
    }

    handleClick() {
        let count = this.state.count;
        count++;

        this.setState({
            count: count
        });
    }

    render() {
        const { id, title } = this.props;

        return (
            <li>
                { id }-{ title }-{ this.state.count }
                <button
                    onClick={() => {
                        this.handleClick();
                    }}
                >+1</button>
            </li>
        );
    }
}

export default TodoItem;

1.4 有狀態元件和無狀態元件

  state用來反映元件內部狀態的變化。

  無狀態元件:如果一個元件的內部狀態是不變的,則用不到state。

  有狀態元件:如果一個元件的內部狀態會發生變化,就需要使用state來儲存變化。

  示例:

  HelloWorld.js

import React from 'react';

function HelloWorld(props) {
    return <h1>Hello { props.name }!</h1>;
}

export default HelloWorld;

  注:由於使用了JSX,需要匯入React。

  index.js

import React from 'react';
import ReactDOM from 'react-dom';

import HelloWorld from './components/HelloWorld'

ReactDOM.render(<HelloWorld name={ 'World' } />, document.getElementById('root'));

  在使用無狀態元件時,儘量定義函式元件。

  在開發React應用時,要先思考哪些元件應該設計成有狀態元件,哪些元件應該設計成無狀態元件。並且,儘可能多的使用無狀態元件,無狀態元件不用關心狀態變化,只聚焦於UI的展示,更容易複用。

  React應用元件設計的一般思路:通過定義少數的有狀態元件管理整個應用的狀態變化,並且將狀態通過props傳遞給其餘的無狀態元件,由無狀態元件完成頁面絕大部分UI的渲染。

  有狀態元件主要關注處理狀態變化的業務邏輯,無狀態元件主要關注元件的UI渲染。

1.5 屬性校驗和預設屬性

1.5.1 屬性校驗

  React提供PropTypes用於校驗元件屬性的型別。

import React from 'react';
import PropTypes from 'prop-types'

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

HelloWorld.propTypes = {
    name: PropTypes.string
}

export default HelloWorld;
import React from 'react';
import ReactDOM from 'react-dom';

import HelloWorld from './components/HelloWorld'

ReactDOM.render(<HelloWorld name={'World'} />, document.getElementById('root'));

  若屬性型別設定number,則報錯提示。

import React from 'react';
import PropTypes from 'prop-types'

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

HelloWorld.propTypes = {
    name: PropTypes.number
}

export default HelloWorld;

import React from 'react';
import PropTypes from 'prop-types'

class HelloWorld extends React.Component {
    render(){
        return (<h1 style={ this.props.style }>Hello { this.props.name }!</h1>);
    }
}

HelloWorld.propTypes = {
    name: PropTypes.string,
    style: PropTypes.shape ({
        color: PropTypes.string,
        fontSize: PropTypes.number
    }).isRequired
}

export default HelloWorld;
import React from 'react';
import ReactDOM from 'react-dom';

import HelloWorld from './components/HelloWorld'

ReactDOM.render(<HelloWorld
    style={{ color: 'red', fontSize: 14 }}
    name={'World'}
/>, document.getElementById('root'));

  示例中,style是一個物件,包含兩個屬性color和fontSize,color是字串型別,fontSize是數字型別。

  如果屬性是元件的必須屬性,在PropTypes的型別屬性上呼叫isRequired。

1.5.2 預設屬性

  React提供為元件屬性指定預設值,元件defaultProps。當元件屬性未被賦值時,元件會使用defaultProps定義的預設屬性。

import React from 'react';

class HelloWorld extends React.Component {
    render(){
        return (<h1 style={ this.props.style }>Hello { this.props.name }!</h1>);
    }
}

HelloWorld.defaultProps = {
    name: 'Libing'
}

export default HelloWorld;
import React from 'react';
import ReactDOM from 'react-dom';

import HelloWorld from './components/HelloWorld'

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

1.6 元件樣式

  為元件新增樣式的方法主要有兩種:外部樣式表和內聯樣式。

1.6.1 外部CSS樣式表

  樣式表引入的兩種方式:

  (1)在使用元件的HTML頁面中通過標籤引入

<link rel="stylesheet" type="text/css" href="style.css" >

  (2)把樣式表當作一個模組,在使用該樣式表的元件中,匯入樣式表檔案

import './style.css'; // 相對路徑

  React元素要使用className代替class作為選擇器。

  /src/components/HelloWorld.css

.hello-world {
    color: red;
    font-size: 14px;
}

  /src/components/HelloWorld.js

import React from 'react';

import './HelloWorld.css';

class HelloWorld extends React.Component {
    render(){
        return (<h1 className='hello-world'>Hello World!</h1>);
    }
}

export default HelloWorld;

  第一種引入樣式表的方式常用於該樣式表作為整個應用的所有元件(基礎樣式表),第二種引入樣式表的方式常用於該樣式表作用於某個元件(元件的私有樣式)。

  全域性基礎樣式表要可以使用第二種方式引入,一般在應用的入口js檔案中引入,如index.js。

1.6.2 內聯樣式

  內聯樣式是一種CSS in JS的寫法:將CSS寫到JS檔案中,用JS物件表示CSS,通過DOM型別節點的style屬性引用樣式物件。

import React from 'react';

class HelloWorld extends React.Component {
    render(){
        return (<h1 style={{
            color: 'red',
            fontSize: '14px'
        }}>Hello World!</h1>);
    }
}

export default HelloWorld;

  style使用了兩個大括號{{}},第一個大括號表示style的值是一個JavaScript表示式,第二個大括號表示這個JavaScript表示式是一個物件。

import React from 'react';

class HelloWorld extends React.Component {
    render(){
        const style = {
            color: 'red',
            fontSize: '14px'
        };
    
        return (<h1 style={ style }>Hello World!</h1>);
    }
}

export default HelloWorld;

2. 元件生命週期

相關文章