10分鐘快速瞭解 React 基礎

React

博客原文css

9102 年了,若是你還不會 React,但願本文能夠幫你快速瞭解 React.js 的基礎知識。html

建立項目

使用 create-react-app 工具快速建立 React SPA。vue

# 建立項目
yarn create react-app my-app

cd my-app

# 開發模式下運行程序
yarn start

項目初始結構:node

my-app/
  README.md
  node_modules/
  package.json
  public/  # 項目使用的公共文件
    index.html # 首頁的模板文件
    favicon.ico # 項目的圖標
    mainifest.json # 移動端配置文件
  src/ # 源代碼
    App.css
    App.js
    App.test.js
    index.css
    index.js # 入口文件
    logo.svg

Hello React

// src/index.js 入口文件
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
// 將根組件渲染到 id 爲 root 的 dom 上
ReactDOM.render(<App />, document.getElementById('root'));
// src/app.js 根組件
import React, { Component } from 'react';
// 建立根組件
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      msg: 'Hello React'
    }
  }
  render() {
    // JSX 語法
    return (
      <div className="App">
        <h1>{ this.state.msg }</h1>
      </div>
    );
  }
}
export default App;

最終這個根組件會在頁面上顯示出內容爲 Hello React 的 h1 標題。react

JSX

上例中在寫根組件時,render 函數中提到了 JSX,簡單的看,就是一個能夠在 js 中寫 html,簡化了經過 React.createElement 建立 Dom,Babel 會將 JSX 轉譯。git

JSX 中有如下幾點須要注意:github

  1. <> 會當作 html 解析 {} 會當作 js 解析;
  2. class 替換爲 className,for 替換爲 htmlFor;
  3. 組件必須有一個最外層根元素包裹,若不想要根元素則可使用 <Fragment>,須要引入 import { Fragment } from 'react'

寫一個 ToDoList 應用

開始寫以前先明確一下一個 ToDoList 的需求:json

  • 一個輸入框輸入要作的事;
  • 一個添加按鈕添加輸入框中的事件到列表中;
  • 一個展現當前已添加事件的列表;
  • 點擊列表中的事件表示已完成,則刪除對應事件;

Todo 組件

先寫一個名爲 Todo 的組件,而後在 App 根組件中調用便可。app

App.js 中調用 Todo 組件。frontend

import React, { Component } from 'react';
import Todo from './Todo'

class App extends Component {
  render() { 
    return ( 
      <Todo></Todo>
    );
  }
}
 
export default App;

調用自定義的組件時直接像原生 html 組件同樣使用 <> ,區別是自定義組件須要以大寫字母開頭。

// Todo.js
import React, { Component, Fragment } from 'react';
import TodoItem from './TodoItem';

class Todo extends Component {
  constructor(props) {
    super(props);
    this.state = { 
      inputVal: '早起',
      list: ['吃早飯', '洗臉刷牙']
    };
    this.inputChange = this.inputChange.bind(this);
    this.addItem = this.addItem.bind(this);
    this.delItem = this.delItem.bind(this);
  }
  render() {
    return (
      <Fragment>
        <div>
          <label htmlFor="todoIpt">todo: </label>
          <input
            id="todoIpt"
            ref={iptRef => this.iptRef = iptRef}
            value={this.state.inputVal}
            onChange={this.inputChange}
          />
          <button onClick={this.addItem}>+</button>
        </div>
        <ul>
          {
            this.state.list.map((item, idx) => {
              return (
                <TodoItem
                  key={idx+item}
                  idx={idx}
                  content={item}
                  delItem={this.delItem}
                />
              )
            })
          }
        </ul>
      </Fragment>
     );
  }
  inputChange() {
    this.setState({
      inputVal: this.iptRef.value
    })
  }
  addItem() {
    this.setState({
      list: [...this.state.list, this.state.inputVal]
    })
  }
  delItem(idx) {
    const list = this.state.list;
    list.splice(idx, 1);
    this.setState({
      list
    })
  }
}
 
export default Todo;

仍然引入 react 及 react.component 並使用 class 建立組件。
constructor 中經過 super 繼承父組件傳入的數據,經過 state 定義組件內部的數據。
render 函數中在 {} 中使用 js 給 html 動態綁定數據及事件,綁定的事件也定義在 class 中,須要經過 bind 修改 this 指向。

這裏使用 ref 將輸入框節點獲取並保存在 this.iptRef 上,在 onchange 事件中修改其綁定的數據 inputVal。
修改數據時須要調用 setState 方法才能出發視圖的更新。

ul 中直接使用 js 的 map 方法遍歷 state.list 生成展現列表,列表中的每一項又單獨抽出來做爲一個新的子組件 TodoItem,並將子組件須要的數據 idx、content 及方法 delItem 傳給他。
須要注意的時遍歷生成的組件若是沒有添加 key 屬性則會報警告。

TodoItem 組件

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class TodoItem extends Component {
  constructor(props) {
    super(props);
    this.state = {};
    this.handleItemClick = this.handleItemClick.bind(this);
  }
  render() {
    return (
      <li onClick={this.handleItemClick}>
        {`${this.props.idx + 1}. ${this.props.content}`}
      </li>
     );
  }
  handleItemClick() {
    this.props.delItem && this.props.delItem(this.props.idx);
  }
}

TodoItem.propTypes = {
  idx: PropTypes.number.isRequired,
  content: PropTypes.string.isRequired,
  delItem: PropTypes.func
}
 
export default TodoItem;

子組件直接經過 props 拿到父組件傳遞的數據包括方法。
子組件無法直接修改父組件傳來的數據,所以須要調用父組件的方法來修改,好比這裏的點擊刪除該項就是調用了父組件的 delItem 方法。

這裏還引入了 prop-types 來幫助子組件進行傳入數據的類型檢查,還能夠添加 isRequired 代表該數據是必需要傳的,若是沒有按照這個限制傳給子組件數據則會有報錯提示。

如今這個需求基本已經完成了。

生命週期

react 的每一個組件都有一套生命週期函數,在組件開始渲染、更新到銷燬的每一個時間點都會執行對應的生命週期函數。

生命週期函數圖譜

上面這個連接能夠看到各類函數的執行順序,最經常使用的 componentDidMount 就相似於 vue 的 mounted。
其中比較特殊的是 shouldComponentUpdate,它能夠在組件更新以前進行攔截,return true 時纔會執行 render 函數。

前面的 ToDoList 程序中,若是在子組件的 render 函數中增長一條 console.log 就會發現輸入框的值每次變化都會觸發全部組件的渲染,所以這裏可使用 shouldComponentUpdate 進行攔截。

TodoItem 組件中添加:

shouldComponentUpdate(nextProps, nextState) {nextProps, nextState);
  return nextProps.content !== this.props.content;
}

代表只有當 content 更新時才執行下一步 render 函數。

總結

到這基本上對 react 有了一個基本的瞭解了。

相關文章
相關標籤/搜索