iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
1
Modern Web

React + GraphQL 全端練習筆記系列 第 3

React 基礎簡介 - Props,State與事件處理

  • 分享至 

  • xImage
  •  

本系列文以製作專案為主軸,紀錄小弟學習React以及GrahQL的過程。主要是記下重點步驟以及我覺得需要記憶的部分,有覺得不明確的地方還請留言多多指教。

雖然有了Components產生畫面,不過總不能一直顯示一樣的東西,而是該根據傳遞的數據更新顯示,在React中,主要的資料流藉由State、Props來產生與傳遞。

這邊只介紹function component中props與state的用法,不包含class component的部分,不過差異只在於怎麼表達,基本觀念是一致的。

Props

JSX中帶入Components時可以加上屬性:

const element = <Welcome name="Sara" />;

這些屬性就會作為props物件傳遞,可以在Component中讀取:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

除了字串,可以用 { } 代入任何javascript變數:

const name = "Sara"

const element = <Welcome name={name}/>;

其實不只變數,只要是javascript表達式都可以:

<MyComponent foo={1 + 2 + 3 + 4} />  //props.foo = 10

可以用樣板字串:

const name = "Sara"

const element = <Welcome greetings={`Hello ${name}!`}/>;

function也可以:

const sayHi = ()=>{
    console.log("Hi!")
    }
    
const element = <Welcome sayHi={sayHi}/>;    

或是

const element = <Welcome 
        sayHi={()=>{
        console.log("Hi!")
        }}
    />;    

可以用javascript物件去理解,比較方便:

const name = "Sara";

const props = {
    foo: 1 + 2 + 3 + 4,
    name: name,
    greetings: `Hello ,${name}`,
    sayHi: () => {
      console.log("Hi!");
    },
};

很多ES6的新功能可以幫助精簡props的表達:

  • 展開運算子:
const props = {
foo: 1 + 2 + 3 + 4,
name: name,
};

//把想要傳遞的東西打包起來,用展開運算子一口氣帶入。
const element = <Welcome {...props}/>;
  • 解構賦值:
function Welcome({foo,name}) {   //const {foo,name} = props
  return <h1>Hello, {name}</h1>;
}

一般是用props帶入在用props.name存取值,不過一開始用解構賦值把變數拉出來,就可以直接使用了。

要注意變數跟key名稱必須一致。

  • Object shorthannd:
const name = "Sara"

const element = <Welcome name/>;  //name ={name}

省略賦值的時候若有同名的變數,就會帶入該變數。

注意如果沒有同名的變數,預設賦值 true。

反過來說若想賦值 true 可以用省略賦值的方式達成,不過不建議這麼做,哪天加了個同名的變數就亂了。

Props 不該被變更(immutable)

數據做為props傳進component後,不應該在components中變更prop,像是

function Welcome(props) {   

  props.name = "Lara"; //你不該這麼做
    
  return <h1>Hello, {props.name}</h1>;
}

像上面的做法並不符合React更新畫面的機制,React更新畫面的主要方式來自於變更State。

State

在function中要使用state的話要透過useState這個hook

import React, { useState } from 'react';

function Example() {
  // 宣告一個新的 state 變數,我們稱作為「count」。
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

跟props一樣,不可以直接對state做變更(immutable):

<button onClick={() => (count + 1)}> //你不該這麼做

這麼做並不會觸發更新,不過用useState宣告每個state的時候都會同時產生對應的更新方法,像是setCount。

<button onClick={() => setCount(count + 1)}>

使用像setCount這類更新state的方法時,除了更新state值外還會發出通知,說有state被更新了,這時候React就會執行render,把更新的部分反映到畫面上。

回到上面props唯讀的問題,那props的值該怎麼更新?

props是從上游傳遞而來,像是把state作為prop傳遞給component,如果希望在子元件中更新這個值的話,就要把更新方法一起傳給子元件:

function Example() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <CountButton count setCount /> //一起傳遞值與他的更新方法
    </div>
  );
}

就能在子元件中達成更新的功能:

function CountButton({ count ,setCount}) {
  return <button onClick={() => setCount(count + 1)}>Click me</button>;
}

總之想更新畫面只能經過State與他的更新方法。

事件處理

而呼叫setState這類方法的時機不外乎處理onclick這類事件的時候。

React中事件處理的邏輯跟一般html沒有多大不同,但是語法上有差異。

html:

<button onclick="activateLasers()">
  Activate Lasers
</button>

JSX:

<button onClick={activateLasers}>
  Activate Lasers
</button>

看出差別了嗎?

  1. 事件名稱: JSX呼叫的事件都是駝峰式(camel case),像是
    • onclick → onClick
    • onmousedown → onMouseDown
  2. 事件呼叫: html用的是字串,JSX則是呼叫javascript物件,而呼叫javascript物件一律用 { } 框起來。

完整版範例:

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

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

handleClick(e)中的 e 是 React特製的 synthetic event,主要是將原生event打包確保跨瀏覽器運作一致,一般使用上沒有大不同,筆記一些常用用法:

  • e.preventDefault() : 阻止預設行為(像是form submit)
  • e.stopPropagation() : 阻止事件在dom tree中向上/下傳遞
  • e.target.value: 取得觸發事件dom的value值

走完React簡介終於要來創專案啦。

References:


上一篇
React 基礎簡介 - React Component 與 Hooks
下一篇
仿Trello - 建立React專案
系列文
React + GraphQL 全端練習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言