為了加入新增看板的功能,我們要來建立第二個元件取名叫做 AddBoard。在 src/components 資料夾中新增 AddBoard 資料夾,然後在 AddBoard 資料夾底下新增名稱為 AddBoard.js 的檔案:
import React from "react";
const AddBoard = () => {
  return (
    <div>
      <button>+新增看板</button>
    </div>
  );
};
export default AddBoard;
並且在 App.js 引入來使用:
import React from 'react';
import { reducer, initialState } from './reducer'; 
// 引入 AddBoard 元件
import AddBoard from "../AddBoard/AddBoard";
const App = () => {
  const [state, dispatch] = React.useReducer(reducer, initialState);
  
  const [isEditingTitle, setIsEditingTitle] = React.useState(false);
  
  React.useEffect(() => {
    document.title = state.title;
  }, [state.title]);
  
  return (
    <div>
      {isEditingTitle ? (
        <input
          value={state.title}
          autoFocus
          onKeyPress={e => {
            if (e.key === "Enter") {
              setIsEditingTitle(false);
            }
          }}
          onChange={e => {
            dispatch({
              type: "CHANGE_TITLE",
              payload: {
                title: e.target.value
              }
            });
          }}
        />
      ) : (
        <h1
          onClick={() => setIsEditingTitle(true)}
        >{state.title}</h1>
      )}
      <div>
        {/* 使用 AddBoard 元件 */ }
        <AddBoard />
      </div>
    </div>
  );
};
export default App;
其中有一個新增看板的按鈕。接下來我們要新增一個 state 來控制是否進入新增模式,若進入新增模式會顯示一個文字輸入框來輸入新看板名稱和一個確定新增看板的按鈕,而在滑鼠點擊別處或是按鈕時就會離開新增模式:
import React from "react";
const AddBoard = () => {
  const [isAddingBoard, setIsAddingBoard] = React.useState(false);
  return (
    <div>
      {isAddingBoard ? (
        <>
          <input autoFocus onBlur={() => setIsAddingBoard(false)} />
          <button onClick={() => setIsAddingBoard(false)}>+新增</button>
        </>
      ) : (
        <button onClick={() => setIsAddingBoard(true)}>+新增看板</button>
      )}
    </div>
  );
};
export default AddBoard;
再來要讓使用者能夠輸入新看板標題,因此我們再新增一個 state 來儲存使用者在文字輸入框輸入的文字:
import React from "react";
const AddBoard = () => {
  const [isAddingBoard, setIsAddingBoard] = React.useState(false);
  const [inputValue, setInputValue] = React.useState('');
  return (
    <div>
      {isAddingBoard ? (
        <>
          <input
            autoFocus
            onBlur={() => setIsAddingBoard(false)}
            // 由 inputValue 來控制文字輸入框內的文字
            value={inputValue}
            // 偵測使用者輸入的事件
            onChange={e => setInputValue(e.target.value)}
          />
          <button onClick={() => setIsAddingBoard(false)}>+新增</button>
        </>
      ) : (
        <button onClick={() => setIsAddingBoard(true)}>+新增看板</button>
      )}
    </div>
  );
};
export default AddBoard;
接著要在使用者按下確定新增的按鈕時新增看板,我們需要呼叫 dispatch 一個新增看板的 action 物件 (在之前一篇文章中定義過新增看板的 action 物件),dispatch 這個函式要透過 props 從 App 元件傳進來才能取得:
App 元件
<AddBoard dispatch={dispatch} />
AddBoard 元件
import React from "react";
// 取得 props 參數
const AddBoard = props => {
  const [isAddingBoard, setIsAddingBoard] = React.useState(false);
  const [inputValue, setInputValue] = React.useState('');
  return (
    <div>
      {isAddingBoard ? (
        <>
          <input
            autoFocus
            onBlur={() => setIsAddingBoard(false)}
            value={inputValue}
            onChange={e => setInputValue(e.target.value)}
          />
          <button
            onClick={() => setIsAddingBoard(false)}
            // 偵測按鈕被點擊的事件
            onMouseDown={() => {
              props.dispatch({
                type: "ADD_BOARD",
                payload: {
                  boardName: inputValue
                }
              });
              // 並且清空文字輸入框內的文字
              setInputValue("");
            }}
          >+新增</button>
        </>
      ) : (
        <button onClick={() => setIsAddingBoard(true)}>+新增看板</button>
      )}
    </div>
  );
};
export default AddBoard;
在 src/components/App 資料夾底下新增 App.module.scss 檔案:
.app {
  min-height: calc(100vh - 96px);
  padding-bottom: 64px;
}
.title {
  color: white;
  padding: 8px;
  
  &:hover {
    text-decoration: underline;
    cursor: pointer; 
  }
}
.titleInput {
  color: black;
}
.boards {
  display: flex;
  align-items: flex-start;
  margin-top: 8px;
}
App 元件引入樣式檔案,並且加入 className(以下僅表示大致元素結構):
import styles from "./App.module.scss";
<div className={styles.app}>
  {isEditingTitle ? (
    <input className={styles.titleInput} />
  ) : (
    <h1 className={styles.title}>
      {state.title}
    </h1>
  )}
  <div className={styles.boards}>
    <AddBoard />
  </div>
</div>
同樣在 src/components/AddBoard 資料夾底下新增 AddBoard.module.scss 檔案:
.addBoard {
  margin-right: 8px;
  border-radius: 4px;
  width: 320px;
  background-color: darkgray;
  padding: 8px;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  .addBoardButton {
    color: white;
  }
  .addButton {
    background: green;
    color: white;
    margin-top: 8px;
    padding: 8px;
    border-radius: 4px;
  }
}
AddBoard 元件引入樣式檔案,並且加入 className(以下僅表示大致元素結構):
import styles from "./AddBoard.module.scss";
<div className={styles.addBoard}>
  {isAddingBoard ? (
    <>
      <input />
      <button className={styles.addButton}>
        +新增
      </button>
    </>
  ) : (
    <button className={styles.addBoardButton}>
      +新增看板
    </button>
  )}
</div>

到目前為止,我們可以輸入新看板名稱,不過按下新增按鈕還看不到新增出來的看板,是因為新看板的資料雖然被新增到 useReducer 的 state 中,但我們並沒有將 state 中的資料顯示出來。
建立看板的元件來顯示看板的資料。