zishu's blog

zishu's blog

一个热爱生活的博主。https://zishu.me

React 學習筆記(二)

React 元素的事件處理和 DOM 元素的很相似,但是有一點語法上的不同

React 事件的命名採用小駝峰式(camelCase),而不是純小寫

使用 JSX 語法時你需要傳入一個函數作為事件處理函數,而不是一個字符串

一、事件處理#

1. 事件綁定#

React 元素的事件處理和 DOM 元素類似,但是在語法上有些區別,比如:

傳統的 html:用雙引號包裹,後面必須跟參數

<button onclick="myfun()">點擊</button>

React:用大括號包裹,後面不跟參數

<button onclick={myfun}>點擊</button>

一個完整的事件函數代碼如下

class Demo extends React.Component {
    render() {

        // 事件函數
        function myfun() {
            alert('helo,world')
        }

        return (
            // 綁定事件
            <button onClick={this.myfun}>
                Activate Lasers
            </button>
        )
    }
}

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

如果方法後面沒有(),則需要為這個方法綁定 this

2. 阻止默認行為#

在 React 中還有一個不同的點,不能通過返回 fasle 阻止默認行為, React 提供了一個屬性--preventDefault,可以通過 preventDefault 阻止腳本執行

看一下傳統的 html 和 React 的對比

<a href="#" onclick="alert('是否彈窗?');return false">
    Click me
</a>

直接在寫上 false 就可以阻止腳本執行

React 通過 preventDefault 屬性阻止腳本執行:

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

二、條件渲染#

在 React 中,可以創建不同的組件來封裝各種你需要的行為,然後,根據應用不同的狀態,你可以只渲染對應狀態下的部分內容。

React 中的條件渲染和 javascript 中的一樣,使用 if 運算符來表示元素當前的狀態,然後讓 React 根據他們來更新 UI。

使用 if..else 語句進行條件渲染#

先寫一個條件渲染的例子,定義了兩個組件,然後通過判斷組件 Greeting 中的變量 isLoggedIn 的真偽,讓瀏覽器渲染組件 UserGreeting 或者 GuestGreeting

// App.js
import React, { Component } from 'react'

export default class App extends Component {
  render() {
    function UserGreeting(props) {
      return <h3>Welcome back!</h3>;
    }

    function GuestGreeting(props) {
      return <h3>Please sign up.</h3>;
    }

    function Greeting(props) {
      const isLoggedIn = props.isLoggedIn;
      if (isLoggedIn) {
        return <UserGreeting />;
      }   
      return <GuestGreeting />;
    }

    return (
      <div>
        <Greeting isLoggedIn={false} />
      </div>
    )
  }
}

最後變量 isLoggedIn 定義了 false,因此,瀏覽器渲染 GuestGreeting

怎麼阻止條件渲染?#

在有些情況下,我們希望能隱藏組件,即使他已經被其他組件渲染。我們可以通過 render 方法返回 null 讓組件不渲染。

下面的示例中, 會根據 prop 中 warn 的值來進行條件渲染。如果 warn 的值是 false,那麼組件則不會渲染:

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return (
    <div className="warning">
      Warning!
    </div>
  );
}

class Page extends React.Component {
  constructor(props) {
    super(props);
    this.state = {showWarning: true};
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }

  handleToggleClick() {
    this.setState(state => ({
      showWarning: !state.showWarning
    }));
  }

  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.handleToggleClick}>
          {this.state.showWarning ? 'Hide' : 'Show'}
        </button>
      </div>
    );
  }
}

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

三、渲染列表#

先看一段代碼,我們使用 map() 函數讓數組中的每一項變雙倍,然後得到一個新的數組 doubled 並打印出來。

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);

// [2,4,6,8,10]

而在 React 中,把數組轉換為元素列表的過程是相似的。

先通過 map() 方法遍歷 numbers 數組,將數組中的每個元素變成 <li> 標籤,最後將得到的數組賦值給 listItems

然後返回 {listItem}

// Map.js
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li>{number}</li>
);

ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

運行之後瀏覽器出現 1-5 的無序列表

1. 分離組件#

上面就是一個基本的列表渲染的例子,但是數據寫死了。接下來我們將數組重構成一個組件,以後再進行數組渲染時,可以輕鬆調用。

// Map.js
export default class Map extends Component {
  render() {

  // 分離出組件 NumberList 作為轉換數組的組件
    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        <li>{number}</li>
      );
      return (
        <ul>{listItems}</ul>
      );
    }

    // 傳入需要的數據
    const numbers = [1, 2, 3, 4, 5, 6, 7];

    return (
      <div>
        <NumberList numbers={numbers} />
      </div>
    )
  }
}

2.key#

image

運行代碼之後,頁面會正常顯示,但是控制台會報一個錯誤。Each child in a list should have a unique "key" prop.,意思是當你創建一個元素時,必須包括一個特殊的 key 屬性。

現在給每個列表元素分配一個 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('root')
);

3. 使用 id 作為 key#

key 幫助 React 識別了哪些元素被改變,比如刪除和添加,所以應當給每個元素確定一個標識,也就是 key

一個元素的 key 最好是這個元素在列表中擁有的一個獨一無二的字符串。通常,我們使用數據中的 id 來作為元素的 key

// Map.js
export default class Map extends Component {
  render() {

    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        <li key={number.id}>  // 賦值 key
          {number.text}
        </li>
      );
      return (
        <ul>{listItems}</ul>
      );
    }

    // 傳入數據
    const numbers = [
      {id: 1,text: 1},
      {id: 2,text: 2},
      {id: 3,text: 3},
      {id: 4,text: 4},
      {id: 5,text: 5}
    ];

    return (
      <Fragment>
        <NumberList numbers={numbers} />
      </Fragment>
    )
  }
}

4. 索引 index 可以作為 key 嗎?#

當元素沒有確定 id 的時候,萬不得已你可以使用元素索引 index 作為 key

const todoItems = todos.map((todo, index) =>
  // 僅僅當沒有確定 id 的時候使用索引index作為 key
  <li key={index}>
    {todo.text}
  </li>
);

如果列表項目的順序可能會變化,我們不建議使用索引來用作 key 值,因為這樣做會導致性能變差,還可能引起組件狀態的問題。

5. 用 key 提取組件#

比方說,如果你提取出一個 ListItem 組件,你應該把 key 保留在數組中的這個 <ListItem /> 元素上,而不是放在 ListItem 組件中的 <li> 元素上。

錯誤的使用方法:

function ListItem(props) {
  const value = props.value;
  return (
    // 錯誤!你不需要在這裡指定 key:
    <li key={value.toString()}>
      {value}
    </li>
  );
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // 錯誤!元素的 key 應該在這裡指定:
    <ListItem value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

正確的使用方法:

function ListItem(props) {
  // 正確!這裡不需要指定 key:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // 正確!key 應該在數組的上下文中被指定
    <ListItem key={number.toString()}              value={number} />

  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

React:一個好的經驗法則是:在 map ( ) 方法中的元素需要設置 key 屬性。

6.key 只是在兄弟節點之間必須唯一#

數組元素中使用的 key 在其兄弟節點之間應該是獨一無二的。然而,它們不需要是全局唯一的。當我們生成兩個不同的數組時,我們可以使用相同的 key 值:

function Blog(props) {
  const sidebar = (
    <ul>
      {props.posts.map((post) =>
        <li key={post.id}>
          {post.title}
        </li>
      )}
    </ul>
  );
  const content = props.posts.map((post) =>
    <div key={post.id}>
      <h3>{post.title}</h3>
      <p>{post.content}</p>
    </div>
  );
  return (
    <div>
      {sidebar}
      <hr />
      {content}
    </div>
  );
}

const posts = [
  {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
  {id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
  <Blog posts={posts} />,
  document.getElementById('root')
);

7.vue 中渲染列表#

Vue 中渲染列表使用的是特殊指令 v-for,其中也有 key 的相關用法

React 中採用的是 map() 方法遍歷數組,然後渲染列表

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。