iT邦幫忙

2022 iThome 鐵人賽

DAY 14
0
Modern Web

用React讓網頁動起來: React基礎與實作系列 第 14

[Day14]用React讓網站動起來:todolist實作-已完成、未完成分頁

  • 分享至 

  • xImage
  •  

昨天已經做出來已完成、未完成的效果了,但是只有style上的轉換,沒有記錄起來。今天要把已完成、未完成的狀態記錄在state中,並做出已完成、未完成的分頁。

儲存狀態

昨天在寫已完成、未完成的切換是在Item component中用isDone這個state偵測狀態,但這樣沒辦法儲存他的狀態,因此我們需要把它儲存在更上層的state中,也就是儲存項目Array的item state。
首先,在新增項目時增加一個isDone的property:

// Input.js

  const clickHandler = (e)=>{
    setItem([...item, {content: input, id: uuidv4(), isDone: false}]);
    setInput("")
  }

並在App中加入doneyet state,來記錄已完成、未完成的事項;此外,寫一個useEffect來偵測item state,當item state發生變化時就更改done state和yet state:

// App.js

const [done, setDone] = useState([]);
const [yet, setYet] = useState([]);

 useEffect(() => {
	// 若項目長度不為0,處理項目
    if (item.length !== 0) {
      const newDone = item.filter(i => i.isDone === true);
      const newYet = item.filter(i => i.isDone === false);

      setDone(newDone);
      setYet(newYet);
    } else {
	  // 若長度為0,則將done、yet設為空Array
      setDone([]);
      setYet([]);
    }
 },[item])

這樣,當項目新增時,便會透過side effect加入yet state中。
接著,要儲存已完成項目,當點選checkbox時,isDone的布林值就會轉換,轉換後的物件會被儲存在App中的item state裡面,且會觸發side effect重新處理doneyet state:

// Item.js

  const checkHandler = (e) => {
	// 轉換isDone的布林值
    let newItem = item.map(i => {
      if (i.id === id) {
        if (e.target.checked) {
          i.isDone = true;
        } else {
          i.isDone = false;
        }
      }

      return i;
    })
    
    setItem(newItem);
    }

  return (
    <Card>
      <Form.Check type="checkbox" id={`check-${id}`} className="d-flex align-items-center">
		{/*加入checkHandler,並且偵測isDone的狀態顯示是否checked*/}
        <Form.Check.Input type="checkbox" className="m-0" onClick={checkHandler} checked={ isDone } />
        {/* … */}
      </Form.Check>
    </Card>
  )

此外,也需要將單一項目的isDone傳入Item component:

// List.js

// …
  const list = itemList.map((i, index)=>{
    const {content, id, isDone} = i;
return (
	{/*…*/}
<Item content={content} id={id} setIsEdit={setIsEdit} item={item} setItem={setItem} done={done} setDone={setDone} yet={yet} setYet={setYet} isDone={isDone}/>
)

這樣就成功儲存已完成、未完成的狀態了,但我們還看不出來,因此要來做做已完成、未完成的分頁。

已完成、未完成分頁

首先,新增一個分頁導覽列Tab component,並把List component放入:

// Tab.js

const Tab = ({item, done, yet, setItem, setDone, setYet}) => {
  return (
    <div>
	  {/*預設顯示「全部」頁*/}
      <Nav variant="tabs" fill defaultActiveKey="all">
        <Nav.Item>
        <Nav.Link eventKey="all" id="all">
          全部
        </Nav.Link>
      </Nav.Item>
        <Nav.Item>
        <Nav.Link eventKey="done" id="done">
          已完成
        </Nav.Link>
      </Nav.Item>
        <Nav.Item>
        <Nav.Link eventKey="yet" id="yet">
          未完成
        </Nav.Link>
      </Nav.Item>
     </Nav>
      <List item={item} done={done} yet={yet} setItem={setItem} setDone={setDone} setYet={setYet}/>
    </div>
  )
}

接著要加入一個state記錄現在在哪一頁,以及使用onClick function偵測換頁:

// Tab.js

  const [tab, setTab]=useState("all");

  const tabHandler = (e)=>{
    setTab(e.target.id);
  }

return (
    <div>
		{/* … */}
        <Nav.Link eventKey="all" id="all" onClick={tabHandler}>
          全部
        </Nav.Link>
		{/* … */}
        <Nav.Link eventKey="done" id="done" onClick={tabHandler}>
          已完成
        </Nav.Link>
		{/* … */}
        <Nav.Link eventKey="yet" id="yet" onClick={tabHandler}>
          未完成
        </Nav.Link>
	{/*…*/}
    </div>
  )

這樣就能實現換頁效果,但是目前葉面上還顯示不出東西,因此我們要使用List component來顯示項目。
List傳入tab state,並根據現在在哪一頁顯示項目:

// Tab.js

// …
// 傳入tab state
      <List tab={tab} item={item} done={done} yet={yet} setItem={setItem} setDone={setDone} setYet={setYet}/>
// List.js

  // …

  // 根據tab判斷itemList要放入哪個Array
  let itemList;
  if(tab==="all"){
    itemList = item;
  }else if(tab === "done"){
    itemList = done;
  }else if(tab==="yet"){
    itemList = yet;
  }

  // 並使用itemList去loop
  const list = itemList.map((i, index)=>{
	// …
  }

最後,把原本在App中的List改成Tab

// App.js

const App = ()=>{
  // …
  return (
    <>
      <Container>
        <Row>
          {/*… */}
              <Input input={input} setInput={setInput} item={item} setItem={setItem}/>
              <Tab item={item} done={done} yet={yet} setItem={setItem} setDone={setDone} setYet={setYet}/>
         {/* … */}
        </Row>
      </Container>
    </>
  )
}

https://ithelp.ithome.com.tw/upload/images/20220929/201468290Eatw07Uiz.png
https://ithelp.ithome.com.tw/upload/images/20220929/20146829JKpr5cb47T.png
https://ithelp.ithome.com.tw/upload/images/20220929/201468294HBB7Rn1yo.png

完整程式碼在這裡:codepen

這樣就完成已完成、未完成狀態切換的功能,以及分頁功能了!


上一篇
[Day13]用React讓網站動起來:todo list 實作-完成、未完成切換
下一篇
[Day15] 用React讓網站動起來:useContext
系列文
用React讓網頁動起來: React基礎與實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言