React(2) - function component & props


Posted by TempuraEngineer on 2022-10-10

目錄


createRoot() 與 render()

React跟Vue一樣都需要一個root,所有在root內的element都由React DOM做管理

// index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App'; // App.js是一個function component,也是root component

// 將#root與React做掛勾
const root = ReactDOM.createRoot(document.getElementById('root'));

// 這裡傳入render的element相當於Vue的App.vue
// 將App渲染出來

// React.StrictMode是一個用來突顯應用程式裡潛在問題的工具,它只會在開發模式中執行
// 如果在開發環境發現render()或constructor被呼叫2次就是因為它
root.render(
  <React.StrictMode> 
    <App />
  </React.StrictMode>
);

Vue3對應寫法

// main.js

import { createApp } from 'vue';
import App from './App.vue'; // root component

const app = createApp(App); // 建立Vue實例

app.mount('#app'); // 把Vue實例掛到root


prop 與 JSX + loop

prop

Props是唯讀的,這邊的唯獨並不是read-only,而是指component不該異動自己的props

假設今天有一個Card組件,上面需要一張圖片,下面顯示文字

為了讓組件可以重複使用,這時就需要prop

function component接收的第一個參數會是prop context,可以用解構將屬性取出

function Card({imgSrc, text}){
  return (
    <div className="flex justify-center flex-col">
      <img src={imgSrc} alt={text} />
      <p className="text-center">{text}</p>
    </div>
  );
}

使用時會長這樣

function App(){
  const data = [
    {url:'https://images.unsplash.com/photo-1462275646964-a0e3386b89fa?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1856&q=80', name:'Unknown'},
    {url:'https://images.unsplash.com/photo-1524316607912-93c3468d9d28?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1169&q=80', name:'Alex'},
    {url:'https://images.unsplash.com/photo-1622022267545-43443d206072?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80', name:'Jill'},
    {url:'https://images.unsplash.com/photo-1616745309504-0cb79e9ae590?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&q=80', name:'Emma'},
  ];

  return (
    <div className="container">
      <div className="grid grid-cols-3 gap-2">
        <Card imgSrc={authorData[0].url} text={authorData[0].name}></Card>
        <Card imgSrc={authorData[1].url} text={authorData[1].name}></Card>
        <Card imgSrc={authorData[2].url} text={authorData[2].name}></Card>
        <Card imgSrc={authorData[3].url} text={authorData[3].name}></Card>
      </div>
    </div>
  );  
}

但這樣如果有50張卡片豈不是要放50次Card🤔

這時就需要用到JSX + loop了,這個方式在Vue對應v-for


JSX + loop

先來做個List組件(Card組件不需要改),並在裡面跑迴圈

function List({data}){
  const elementArr = [];

  for(let i = 0; i < data.length; i++){
    elementArr.push(<Card imgSrc={data[i].url} text={data[i].name} key={i}></Card>);
  }

  return <div className="grid grid-cols-3 gap-2">{elementArr}</div>;
}

或者

function List({data}){
  const elementArr = data.map(i => <Card imgSrc={i.url} text={i.name}></Card>);

  return <div className="grid grid-cols-3 gap-2">{elementArr}</div>;
}

再或者

function List({data}){
  return (
    <div className="grid grid-cols-3 gap-2">
      {data.map(i => <Card imgSrc={i.url} text={i.name}></Card>)}
    </div>
  );
}

以上不管哪種,在App使用時都長這樣,簡潔多了

function App(){
  const data = [
    {url:'https://images.unsplash.com/photo-1462275646964-a0e3386b89fa?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1856&q=80', name:'Unknown'},
    {url:'https://images.unsplash.com/photo-1524316607912-93c3468d9d28?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1169&q=80', name:'Alex'},
    {url:'https://images.unsplash.com/photo-1622022267545-43443d206072?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80', name:'Jill'},
    {url:'https://images.unsplash.com/photo-1616745309504-0cb79e9ae590?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&q=80', name:'Emma'},
  ];

  return (
    <div className="container">
      <div className="grid grid-cols-3 gap-2">
        <List data={data}></List>
      </div>
    </div>
  );  
}

跳回去,如果另一個地方的List組件裡面要放FlipCard呢🤔

function FlipCard({imgSrc, text}){
  return (
    <div className="flip-card">
      <div className="flip-card-inner">
        <div className="flip-card-front">
          <img src={imgSrc} alt="" className="w-full rounded-full"/>
        </div>

        <div className="flip-card-back">
          <h1>{text}</h1>
        </div>
      </div>
    </div>
  );
}

為此需要新增一個ele prop用來傳組件進去,但注意如果List內的組件有prop的話不要直接傳組件給ele

function List({data, ele, className}){
  const elementArr = [];

  for(let i = 0; i < data.length; i++){
    // ele這個prop是個函式,它接收的參數是組件的prop,呼叫後會回傳component
    // 使用展開運算子將資料依序傳入ele()
    elementArr.push(ele(...Object.values(data[i]), i));
  }

  return <div className={className}>{elementArr}</div>
}

使用時會長這樣

這邊之所以不直接將Card組件傳入ele,因為迴圈在List組件裡跑,這時還取不到資料傳給Card的prop,如果直接傳組件渲染出來會一片空白

所以傳一個會回傳組件的函式,傳資料給Card的prop的任務就交給List

function App(){
  const data = [
    {url:'https://images.unsplash.com/photo-1462275646964-a0e3386b89fa?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1856&q=80', name:'Unknown'},
    {url:'https://images.unsplash.com/photo-1524316607912-93c3468d9d28?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1169&q=80', name:'Alex'},
    {url:'https://images.unsplash.com/photo-1622022267545-43443d206072?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80', name:'Jill'},
    {url:'https://images.unsplash.com/photo-1616745309504-0cb79e9ae590?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=580&q=80', name:'Emma'},
  ];

  return (
    <div className="container">
      <List data={data}  ele={(url, name, index) => {return <Card imgSrc={url} text={name} key={index}></Card>}} className="grid grid-cols-3 gap-2"></List>

      <hr className="my-8"/>

      <List data={data}  ele={(url, name, index) => {return <FlipCard imgSrc={url} text={name} key={index}></FlipCard>}} className="flex justify-around"></List>
    </div>
  );
}


參考資料

Render Element
Components 與 Props
列表與 Key
Loop inside React JSX


#React #Function component #prop







Related Posts

CH1. 物件導向軟體開發簡介

CH1. 物件導向軟體開發簡介

HTML \ CSS 初學者易混淆觀念 + 表單樣式實作

HTML \ CSS 初學者易混淆觀念 + 表單樣式實作

申請 Google 快速登入會員功能

申請 Google 快速登入會員功能


Comments