iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 7
0
Modern Web

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

仿Trello - 建立基礎 List 部件

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

製作NavBar部件

前回寫在KanBan裡的NavBar部件太大一串了,先抽離這個部分,之後再回來改。

在components資料夾底下製作KanBanNav.jsx

// KanBanNav.jsx
import React from "react";
import {
  Navbar,
  Nav,
  NavDropdown,
  Form,
  FormControl,
  Button,
} from "react-bootstrap";

export default function KanBanNav() {
  return (
    <Navbar expand="lg">
      <Navbar.Brand href="#home">React-Bootstrap</Navbar.Brand>
      <Navbar.Toggle aria-controls="basic-navbar-nav" />
      <Navbar.Collapse id="basic-navbar-nav">
        <Nav className="mr-auto">
          <Nav.Link href="#home">Home</Nav.Link>
          <Nav.Link href="#link">Link</Nav.Link>
          <NavDropdown title="Dropdown" id="basic-nav-dropdown">
            <NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
            <NavDropdown.Item href="#action/3.2">
              Another action
            </NavDropdown.Item>
            <NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
            <NavDropdown.Divider />
            <NavDropdown.Item href="#action/3.4">
              Separated link
            </NavDropdown.Item>
          </NavDropdown>
        </Nav>
        <Form inline>
          <FormControl type="text" placeholder="Search" className="mr-sm-2" />
          <Button>Search</Button>
        </Form>
      </Navbar.Collapse>
    </Navbar>
  );
}

跟原本的KanBan基本一樣,然後回到KanBan做清理跟載入

// KanBan.jsx
import React from "react";
import KanBanNav from "./KanBanNav"; //載入

export default function KanBan() {
  return (
     <KanBanNav></KanBanNav> //清除掉原本的之後加上
  );
}

製作Todo部件

做List會用到Todo部件,所以先做這部分。

//Todo.jsx
import React from "react";

export default function Todo() {
  return <div className="todo my-1 p-1 rounded">Todo1</div>;
}

目前只簡單顯示寫死的Todo名稱,外加一些造型。

製作List部件

//List.jsx
import React from "react";
import Todo from "./Todo";

export default function List() {
  return (
    <div className="list p-2 m-1 rounded-lg">
      <div className="title">List1</div>
      <Todo></Todo>
      <Todo></Todo>
    </div>
  );
}

寫死的標題之外掛上兩個Todo,後面在改寫成動態載入的。

然後掛到KanBan上

import React from "react";
import { Container, Row } from "react-bootstrap";
import KanBanNav from "./KanBanNav";
import List from "./List";

export default function KanBan() {
  return (
    <span>
      <KanBanNav></KanBanNav>
      <Container fluid className="board p-1">
        <Row className="m-0">
          <List></List>
          <List></List>
        </Row>
      </Container>
    </span>
  );
}

用Bootstrap Grid讓List從左到右並列。

完成畫面,看到並列的List1,各帶兩個Todo1。

這邊已經有用Sass加上顏色方便辨識,關於Sass預計之後統整一篇介紹,這邊先跳過。

以上過程中的心得:

  • 拆分部件的流程基本有兩個:

    1. 全寫在一個部件後再從中拆出來
    2. 預先訂製好小部件再用在大部件上

    2就比較需要經驗判斷,如果是清單的構造就很好想,不過有些時候要拆多細還要根據部件的功能思考,會不會在其他地方用到? 是不是帶入新的props就能讓部件能夠重複使用?
    不清楚的時候還是先用1的方式做做看,再想想有沒有需要拆、有沒有辦法拆吧。

假資料跟迴圈

上面部件裡的標題、名稱都是寫死的,現在要改用帶入資料的方式去動態顯示每個部件的內容。

首先建假資料:

export default function KanBan() {
  const dummyData = [
    {
      title: "list1",
      todos: [
        {
          name: "todo1",
          finished: false,
        },
        {
          name: "todo2",
          finished: false,
        },
      ],
    },
    {
      title: "list2",
      todos: [
        {
          name: "todo3",
          finished: false,
        },
        {
          name: "todo4",
          finished: false,
        },
      ],
    },
  ];
  
  ...
  
  }

這邊用陣列包含兩個list物件,各自有標題、包含的todo陣列,todo的名稱與是否完成的資訊。
用陣列的原因是為了方便在JSX中用迴圈的方式加載部件,下面會介紹
接著用dummyData做成state

import React, { useState } from "react"; //載入useState方法

export default function KanBan() {

  const dummyData = [...];

  const [lists, updateLists] = useState(dummyData); //建立state

}

useState接收dummyData作為state的初始值,回傳存取state的變數lists, 以及之後用於更新state的方法updateLists。

然後就能用迴圈的方式產生動態的List物件:

export default function KanBan() {

  const dummyData = [...];  

  const [lists, updateLists] = useState(dummyData);

  return (
    <span>
      <KanBanNav />
      <Container fluid className="board p-1">
        <Row className="m-0">
          {lists.map((list, index) => (
            <List key={index} {...list} /> //用展開運算子載入props
          ))}
        </Row>
      </Container>
    </span>
  );
 }

這邊有個帶props的小技巧,如果state是個包含許多key的物件,可以用ES6的展開運算子全部帶成props。

到List裡接收props:

// List.jsx
export default function List({ title, todos }) {
  return (
    <div className="list p-2 m-1 rounded-lg">
      <div className="title">{title}</div>  //帶入標題
      {todos.map((todo, index) => (  //產生todo清單
        <Todo key={index} name={todo.name} />
      ))}
    </div>
  );
}

跟帶入props一樣,接收props可以利用解構賦值的方式存取,比較一下有無用解構賦值的差別:

// 直接用解構賦值
export default function List({ title, todos }) {
    ...
}


//載入props後再解構賦值
export default function List(props) {

    const { title, todos } = props
    ...
}

//不用解構賦值
export default function List(props) {

    const title = props.title
    const todos = props.todos
    ...
}

當props很多的時候直接解構賦值能少寫很多行,也更直接看出這個部件需要那些props,不過要注意傳入、解構的變數名稱必須相同。

最後傳資料給Todo:

//Todo.jsx
import React from "react";

export default function Todo({ name }) {
  return <div className="todo my-1 p-1 rounded">{name}</div>;
}

到目前的畫面:

可以看到清單的標題,代辦事項的名稱都根據提供的資料變更了。

到這裡基礎的清單就建好了,接著製作新增代辦事項的功能。


上一篇
仿Trello - 使用React Bootstrap
下一篇
仿Trello - 建立新增Todo介面
系列文
React + GraphQL 全端練習筆記30

尚未有邦友留言

立即登入留言