1. 程式人生 > >React學習筆記之react基礎篇(2)

React學習筆記之react基礎篇(2)

應用場景 組件 單元 ren provide form 實例 show wid

  上一節我已經對React中基本的組件操作進行了說明,這一節我將對組件的一些附加屬性(如:組件的生命周期和組件的樣式)以及一些其他功能進行講解

一.組件的樣式

1.外部CSS樣式表:

//style.css
.foo{
    width:100%;
    height:50px;
}

//引入的兩種方式

1.在使用組件的HTML頁面中通過標簽引入
<link rel="stylesheet" type="text/css" href="style.css">

2.在組件中添加入該模塊
import ‘./style.css‘;

  說明:使用css樣式表經常遇到的問題就是clsss名稱沖突,業內解決這個問題的一個常用方案就是使用 CSS Modelus。

2.內聯樣式

function Welcome(props){
    return(
        <h1
            style={{                              //第一個括號表示JavaScript表達式,第二個括號表示這個JavaScript表達式是一個對象
                width:"100%",
                height:"50px",
                backgroundColor:"blue"            //必須使用駝峰命名法
               }}
         >
              Hello,{props.name}
         </h1>
    );
}   

  

二.組件生命周期

通常,組件的生命周期可以分成三個階段:掛載階段丶更新階段丶卸載階段

 1.掛載階段 

 這個階段組件被創建,執行初始化,並被掛載到DOM中,完成組件的第一次渲染。

 1.constructor

 組件被創建時,會首先調用組件的構造方法,通常用於初始化組件的state以及綁定事件處理方法等工作

constructor(props,context) {
  super(props,context)
  console.log(this.props,this.context)               // 在內部可以使用props和context
}

 當然如果你只需要在構造函數內使用props或者context,那麽只傳入一個參數即可,如果都不可以,就都不傳。 

 2.componentWillMount

   這個方法在組件被掛載到DOM前調用,而且只會被調用一次,很少使用,因為它能完成的工作都可以讓constructor去完成。

 3.render

   這是定義組件唯一必要的方法(組件的其他生命周期方法都可以不寫)。render函數會插入JSX生成的dom結構,react會生成一份虛擬dom樹,在每一次組件更新時,在此react會通過其diff算法比較更新前後的新舊DOM樹,比較以後,找到最小的有差異的DOM節點,並重新渲染。同時在render中不能調用this.setState,因為這會改變組件的狀態。

 4.componentDidMount

   這個方法在組件掛載到DOM後進行調用,而且只會被調用一次。這個方法通常用於向服務器請求數據,在這個方法中調用this.setState會引起組件的重新渲染

 2.更新階段

 組件被掛載到DOM後,組件的props或state可以引起組件更新。props由父組件的render方法被調用引起,state通過調用this.setState修改組件的state來進行觸發的。

 1.componentWillReceiveProps(nextProps)

   通過對比nextProps和this.props,將nextProps setState為當前組件的state,從而重新渲染組件

 2.shouldComponentUpdate(nextProps,nextState)

   通過比較nextPorps丶nextState和組件當前的props丶state決定這個方法的返回結果。若返回true則繼續渲染,否則後續的componentWillUpdate丶coponentDidUpdate方法不會進行調用,可以減少不必要的渲染。

 3.componentWillUpdate(nextProps,nextState)

   這個方法在組件render調用前執行,可以作為組件更新發生前執行某些工作的地方,同時該方法不能調用setState。

 4.coponentDidUpdate(prevProps,prevState)

   這個方法在組件更新後進行調用,可以作為操作更新後DOM的方法,同時該方法不能調用setState.

 3.卸載階段

 組件從DOM中被卸載的過程,這個過程中只有一個生命周期方法:

 1.componentWillUnmount()

   在組件被清理前進行調用,可以執行一些清理操作。

三.列表和Keys

React示例

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((numbers) =>
  <li>{numbers}</li>
);
 
ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById(‘example‘)
);

我們可以將以上實例重構成一個組件,組件接收數組參數,每個列表元素分配一個 key,不然會出現警告 a key should be provided for list items,意思就是需要包含 key:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}
 
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById(‘example‘)
);

  

四.表單

  HTML 表單元素與 React 中的其他 DOM 元素有所不同,因為表單元素生來就保留一些內部狀態。在 HTML 當中,像<input>, <textarea>, 和 <select> 這類表單元素會維持自身狀態,並根據用戶輸入進行更新。但在React中,可變的狀態通常保存在組件的狀態屬性中,並且只能用 setState() 方法進行更新。為了讓表單元素的狀態的變更也能通過組件的state管理,React采用受控組件的技術達到這一目的。

1.受控組件

  如果一個表單元素的值是由React進行管理的,那它就是一個受控組件

  示例:

class HelloMessage extends React.Component {
  constructor(props) {
      super(props);
      this.state = {value: ‘Hello Runoob!‘};                             //對數據進行初始化
      this.handleChange = this.handleChange.bind(this);
  }
 
  handleChange(event) {                              //對數據進行更新
    this.setState({value: event.target.value});
  }
  render() {
    var value = this.state.value;
    return <div>
            <input type="text" value={value} onChange={this.handleChange} /> 
            <h4>{value}</h4>
           </div>;
  }
}
ReactDOM.render(
  <HelloMessage />,
  document.getElementById(‘example‘)
);

  示例二:

  在以下實例中我們將為大家演示如何在子組件上使用表單。 onChange 方法將觸發 state 的更新並將更新的值傳遞到子組件的輸入框的 value 上來重新渲染界面。你需要在父組件通過創建事件句柄 (handleChange) ,並作為 prop (updateStateProp) 傳遞到你的子組件上。

class Content extends React.Component {
  render() {
    return  <div>
            <input type="text" value={this.props.myDataProp} onChange={this.props.updateStateProp} /> 
            <h4>{this.props.myDataProp}</h4>
            </div>;
  }
}
class HelloMessage extends React.Component {
  constructor(props) {
      super(props);
      this.state = {value: ‘Hello Runoob!‘};
      this.handleChange = this.handleChange.bind(this);
  }
 
  handleChange(event) {
    this.setState({value: event.target.value});
  }
  render() {
    var value = this.state.value;
    return <div>
            <Content myDataProp = {value} 
              updateStateProp = {this.handleChange}></Content>
           </div>;
  }
}
ReactDOM.render(
  <HelloMessage />,
  document.getElementById(‘example‘)
);

  

2.非受控組件

  非受控組件是指表單元素的狀態依然由表單元素自己管理,而不是交給React組件管理。使用非受控組件需要由一種方式可以獲取到表單元素的值,React中提供了一個特殊的屬性ref,用來引用React組件或DOM元素的實例,因此我們可以通過為表單元素定義ref屬性獲取元素的值。

  示例:

class Simple extends Component{
    constructor(props){
        super(props);
        this.handleSubmit=this.handleSubmit.bind(this);
}

handleSubmit(event){
    //通過this.input獲取到input元素的值
    alert(‘this.input.value‘);
    event.preventDefault();                                                //preventDefault() 方法阻止元素發生默認的行為,即阻止表單提交
}

render(){
    return(
        <form onSubmit = {this.handleSubmit)>
            <label>
                title:
              {/*this.input指向當前input元素*/}
                <input type="text" defaultValue="something" ref={(input)=>this.input=input}/>    //通過defaultValue為元素設置默認值,同時通過ref函數接收函數作為參數進行數據引用。
                </label>
                <input type="submit" value="Submit" />
            </form>
        );
    }
}

五.React16新的返回值類型

React16之前,render方法必須返回單個元素。現在render方法支持兩種新的返回類型:數組字符串

示例(數組):

class ListComponent extends Component{
    render(){
        return [
            <li key="A">First item</li>,
            <li key="B">Second item</li>,
            <li key="C">Third item</li>
        ];
    }
}

示例(字符串):

class StringComponent extends Component{
    render(){
        return "Just a Strings";
    }
}

六.錯誤處理

  組件在運行期間如果執行出錯就會阻塞整個頁面的渲染,這時候只能刷新頁面才能回復應用。react16提供了一種友好的錯誤處理方式-----錯誤邊界。錯誤邊界是能夠捕捉子組件的錯誤並對其進行優雅處理的組件。優雅處理可以是輸出錯誤日誌丶顯示出錯提示等。

   定義componentDidCatch(error,info)這個方法的組件將成為一個錯誤邊界。

 示例:

import React, { Component } from "react";

const Profile = ({ user }) => <div>name: {user.name}</div>;

class ErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(err, info) {
    // 顯示錯誤UI
    this.setState({ hasError: true });
    // 同時輸出錯誤日誌
    console.log(err, info);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Oops, something went wrong!</h1>;
    }
    return this.props.children;
  }
}

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      user: { name: "react" }
    };
  }

  // 將user置為null,模擬異常
  onClick = () => {
    this.setState({ user: null });
  };

  render() {
    return (
      <div>
        <ErrorBoundary>
          <Profile user={this.state.user} />
        </ErrorBoundary>
        <button onClick={this.onClick}>更新</button>
      </div>
    );
  }
}

export default App;

  點擊按鈕之後因為user為null,所以程序就會拋出異常並且被ErrorBoundary捕捉並在界面上顯示錯誤提示信息。

七.Portals定義全局配置

 React16的Portals特性讓我們可以把組件渲染到當前組件樹以外的DOM節點上,這個特性典型的應用場景是渲染應用的全局彈框

  Portals的實現依賴ReactDOM的一個新的API:

ReactDOM.createPortal(可以被渲染的節點,需要掛載的節點)

  示例:

import React, { Component } from "react";
import ReactDOM from "react-dom";                      //因為需要使用ReactDOM中的API所以需要引入對應的庫

class Modal extends Component {
  constructor(props) {
    super(props);
    this.container = document.createElement("div");           //創建一個div節點
    document.body.appendChild(this.container);              //將div節點綁定到根節點下面
  }

  componentWillUnmount() {                          //從根節點移除div節點
    document.body.removeChild(this.container);
  }

  render() {
    return ReactDOM.createPortal(                      //創建的DOM樹掛載到this.container指向的div節點下面
      <div className="modal">
        <span className="close" onClick={this.props.onClose}>
          ×
        </span>
        <div className="content">{this.props.children}</div>
      </div>,
      this.container
    );
  }
}

class App extends Component {
  constructor(props) {
    super(props);
    this.state = { showModal: true };
  }

  closeModal = () => {
    this.setState({ showModal: false });
  };

  render() {
    return (
      <div>
        <h2>Dashboard</h2>
        {this.state.showModal && (
          <Modal onClose={this.closeModal}>Modal Dialog </Modal>
        )}
      </div>
    );
  }
}

export default App;

  

八.自定義DOM屬性

  react16之前會忽略不識別的HTML屬性,現在react會把不識別的屬性傳遞給DOM元素作為一個新的屬性。

 示例:

<div custom="one"  />

 在瀏覽器中渲染出的DOM節點為:

<div />

 而react16渲染出的DOM節點為:

<div custom="one" />

  

React學習筆記之react基礎篇(2)