2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

基礎から学ぶReact/React Hooks学習メモ 7 Chakra UIでアプリにデザインを組み込む

Posted at

7 Chakra UIでアプリにデザインを組み込む

参考
基礎から学ぶReact/React Hooks

Chakra UIとは?

  • カスタマイズ可能なReact UIコンポーネント
  • 定番コンポーネントが提供されている

Default Theme

  • Default Themeから継承や追加ができる

Style Props

  • コンポーネントにpropsを渡すだけでコンポーネントのスタイルを変更する

ChakraUIのインストール

yarn add @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4
  • Chakra UI iconsのインストール
yarn add @chakra-ui/icons

themeファイルの追加

src/
┣ apis/
┃ ┗ todos.js
┣ components/
┃ ┣ App.js
┃ ┣ TodoAdd.js
┃ ┣ TodoItem.js
┃ ┣ TodoList.js
┃ ┗ TodoTitle.js
┣ hooks/
┃ ┗ useTodo.js
┣ theme/       ← 追加
┃ ┗ theme.js   ← 追加
┗ index.js
  • グローバルなテーマを設定する
src\theme\theme.js
import { extendTheme } from "@chakra-ui/react";

const theme = extendTheme({
  styles: {
    // グローバルなテーマの上書き、追加
    global: {
      body: {
        // bodyに指定したいstyle
        backgroundColor: "orange.50",
        color: "gray.800",
      },
      p: {
        // mdを境に、PCとSP表示を切り替える
        fontSize: { base: "md", md: "lg" },
        // 文字列の行の間隔
        lineHeight: "tall",
      },
    },
  },
});

export default theme;
  • Providerの指定をする
    • トップルートでChakraProviderの設定が必要
    • themeの設定を渡す
  • ChakraProviderには、resetCSSが含まれている。
    • resetCSSを使用しない場合、ChakraProviderresetCSS={false}を追加する
  • src\index.js
src\index.js
import React from "react";
import ReactDOM from "react-dom";
import { ChakraProvider } from "@chakra-ui/react";
import theme from "./theme/theme";
import App from "./components/App";

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <ChakraProvider theme={theme}>
      <App />
    </ChakraProvider>
  </React.StrictMode>,
  rootElement
);
  • src\components\App.js
    • Container で全体を囲む
      • centerContent でセンタリング
      • p={{ base: "4", md: "6" }}
      • maxWidth="3xl"
    • TodoTitle
      • fontSize={{ base: "2xl", md: "3xl" }}
    • TodoAdd
    • TodoList
      • fontSize={{ base: "xl", md: "2xl" }}
src\components\App.js
import React, { useRef } from "react";

import { Container } from "@chakra-ui/react";
import { AddIcon } from "@chakra-ui/icons";

import { useTodo } from "../hooks/useTodo";
import { TodoTitle } from "./TodoTitle";
import { TodoAdd } from "./TodoAdd";
import { TodoList } from "./TodoList";

function App() {
  const { todoList, addTodoListItem, toggleTodoListItemStatus, deleteTodoListItem } = useTodo();

  const inputEl = useRef(null);

  const handleAddTodoListItem = () => {
    if (inputEl.current.value === "") {
      return;
    }
    addTodoListItem(inputEl.current.value);
    inputEl.current.value = "";
  };

  console.log("TODOリスト:", todoList);

  // 未完了リスト
  const incompletedList = todoList.filter((todo) => !todo.done);
  // 完了リスト
  const completedList = todoList.filter((todo) => todo.done);

  return (
    <>
      <Container centerContent p={{ base: "4", md: "6" }} maxWidth="3xl">
        <TodoTitle title="TODO進捗管理" as="h1" fontSize={{ base: "2xl", md: "3xl" }} />
        <TodoAdd placeholder="ADD TODO" leftIcon={<AddIcon />} buttonText="TODOを追加" inputEl={inputEl} handleAddTodoListItem={handleAddTodoListItem} />
        <TodoList
          todoList={incompletedList}
          toggleTodoListItemStatus={toggleTodoListItemStatus}
          deleteTodoListItem={deleteTodoListItem}
          title="未完了TODOリスト"
          as="h2"
          fontSize={{ base: "xl", md: "2xl" }}
        />
        <TodoList
          todoList={completedList}
          toggleTodoListItemStatus={toggleTodoListItemStatus}
          deleteTodoListItem={deleteTodoListItem}
          title="完了TODOリスト"
          as="h2"
          fontSize={{ base: "xl", md: "2xl" }}
        />
      </Container>
    </>
  );
}

export default App;
  • src\components\TodoAdd.js
    • textareaをTextareaに変更
      • mt="8"
      • borderColor="gray.400"
    • buttonをButtonに変更
      • colorScheme="blue"
      • leftIcon={leftIcon}
      • mt="8"
src\components\TodoAdd.js
import { Textarea, Button } from "@chakra-ui/react";

export const TodoAdd = ({ placeholder, leftIcon, buttonText, inputEl, handleAddTodoListItem }) => {
  return (
    <>
      <Textarea placeholder={placeholder} mt="8" borderColor="gray.400" ref={inputEl} />
      <Button onClick={handleAddTodoListItem} colorScheme="blue" leftIcon={leftIcon} mt="8">
        {buttonText}
      </Button>
    </>
  );
};
  • src\components\TodoItem.js
    • ListItemで全体を囲む
    • 文字列は、Textで囲む
    • Flexでボタンを囲む
    • buttonをButtonに変更
    • buttonをIconButtonに変更
src\components\TodoItem.js
import { ListItem, Text, Flex, Button, IconButton } from "@chakra-ui/react";
import { DeleteIcon } from "@chakra-ui/icons";

// 1つのTodo、内容と移動・削除ボタン
export const TodoItem = ({ todo, toggleTodoListItemStatus, deleteTodoListItem }) => {
  // onClickイベントが発生したら、useTodoフックを呼び出す
  const handleToggleTodoListItemStatus = () => toggleTodoListItemStatus(todo.id, todo.done);
  const handleDeleteTodoListItem = () => deleteTodoListItem(todo.id);
  const label = todo.done ? "未完了リストへ" : "完了リストへ";
  const setColorScheme = todo.done ? "ping" : "blue";

  return (
    <ListItem borderWidth="1px" p="4" mt="4" bg="white" borderRadius="md" borderColor="gray.300">
      <Text mb="6">{todo.content}</Text>
      <Flex align="center" justify="flex-end">
        <Button colorScheme={setColorScheme} variant="outline" size="sm" onClick={handleToggleTodoListItemStatus}>
          {label}
        </Button>
        <IconButton icon={<DeleteIcon />} variant="unstyled" aria-label="delete" onClick={handleDeleteTodoListItem}>
          削除
        </IconButton>
      </Flex>
    </ListItem>
  );
};
  • src\components\TodoList.js
    • TodoTitle
      • fontSize={fontSize}
      • mt="12"
    • ulをListに変更
      • w="full"
src\components\TodoList.js
import { List } from "@chakra-ui/react";

import { TodoTitle } from "./TodoTitle";
import { TodoItem } from "./TodoItem";

// TodoItemをループして表示
// todoListが0件の場合、タイトルとTODOリストを表示しない
export const TodoList = ({ fontSize, todoList, toggleTodoListItemStatus, deleteTodoListItem, title, as }) => {
  return (
    <>
      {todoList.length !== 0 && (
        <>
          <TodoTitle title={title} as={as} fontSize={fontSize} mt="12" />
          <List w="full">
            {todoList.map((todo) => (
              <TodoItem todo={todo} key={todo.id} toggleTodoListItemStatus={toggleTodoListItemStatus} deleteTodoListItem={deleteTodoListItem} />
            ))}
          </List>
        </>
      )}
    </>
  );
};
  • src\components\TodoTitle.js
    • h1をHeadingに変更
    • mt={mt}
    • as={as}
    • fontSize={fontSize}
    • w="full"
src\components\TodoTitle.js
import React, { memo } from "react";
import { Heading } from "@chakra-ui/react";

// タイトルの表示コンポーネント
export const TodoTitle = memo(({ title, as, fontSize, mt }) => {
  return (
    <Heading mt={mt} as={as} fontSize={fontSize} w="full">
      {title}
    </Heading>
  );
});

完成

image.png

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?