Reactの基礎を学びながらTodoアプリを作成していく。
まず、Reactの雛形を作成していく。
ターミナル(Windowsの場合はcommand prompt)を開いて以下のように打つ。
npx create-react-app react-tutorial
cd react-tutorial
code .
まず最初の一行で、Reactの雛形を作成していく。そのとき、プロジェクトをまとめておくディレクトリ内で実行すると良い。
最初の行の最後 "react-tutorial"という部分はプロジェクトが作成されるディレクトリ名。そのため、自分で自由に決めていい。
そうしたら、作成されたディレクトリに移動して、その階層でコードエディタを開く。
作成されたディレクトリ内でindex.htmlの記述を見る。
シンプルな構造でheadタグのtitleの要素をいじるとWebページのタイトルを変更することが出来る。
bodyタグのdivについているrootというidがついているがそれが重要である。この後説明する。
そして、src(ソース)/App.jsの中のApp関数の部分がターミナル上で実行されるWebページの画面である。
実際に、ターミナル上で
npm start
と入力すると以下のようにApp.jsの内容が表示される。
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
必要ないのでReactのロゴの画像とApp.jsのApp関数内の記述、index.js内の"reportWebVitals"に関する記述を削除する。
ちなみに、"reportWebVitals"に関する記述は恐らくであるが、Webページが表示される際のメトリクスを集計する機能だと思われる。
扱えるようになるには少々時間がかかりそうだ。
結果として残した記述は以下のようになる。
src/App,js
import './App.css';
function App() {
return <div className="App"></div>;
}
export default App;
src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
少々解説をすると、index.jsではindex.html内のidがrootであるdivタグを取得して、そこに対しレンダリングを行っている。
ここでは以下の3つの要素、意味をなす要素としては1つだけをレンダリングしている。
<React.StrictMode>
<App />
</React.StrictMode>
ちなみに、レンダリングの意味はスクリプトなどの抽象的なデータ集合をもとに一定の処理を行ってブラウザのページなどに内容を描写することを指している。
この場合、AppというのがApp.jsで定義された関数でそれをレンダリングしていることになる。
そしれ、Appを挟んでいるReact.StrictModeというのはなにかコードに脆弱性を発見したり、トラブルを発見したりしたらエラーを出してくれる厳密なモードで実行するという意味になる。外しても実行はされるが、基本的にアプリ開発ではこれをつけておいた方がいい。
App.js内に”Hello React"という記述を加えて、ブラウザ内に表示させたい。
import './App.css';
function App() {
return <div className="App">Hello React</div>;
}
export default App;
divタグの中に”Hello React"という記述をした。
なぜ、中央寄りになるのかというと、App.cssが反映されているためである。その中の記述を変更することで表示の内容を変えられる。
また、Reactにはホットリローディング機能が備わっていて、変更があれば自動的に変更を反映してくれる。
Reactはコンポーネントが開発の基本となる。
import './App.css';
function App() {
return (
<div className="App">
<TodoList/>
</div>
);
}
export default App;
App.js内のdivタグの中に”<TodoList/>"というコンポーネントというタブを作成した。これがコンポーネントになる。
ただし、現状では”TodoList"はまだ定義されていませんとエラーが返ってくる。
コンポーネントを実装するために、srcディレクトリ内に”TodoList.jsx"というファイルを作成する。
VScodeを使用している場合下に示した拡張機能を使用するとコンポーネントの作成がしやすい。
こちらの拡張機能を入れて、"TodoList.jsx"の中で”rafce"と入力して変換を押すと以下のように自動でコンポーネントの雛形を作成してくれる。
import React from 'react'
const TodoList = () => {
return (
<div>TodoList</div>
)
}
export default TodoList
const TodoList = () => {
return (
<div>TodoList</div>
)
}
この部分がコンポーネントであり、この場合App.jsで”<TodoList/>"という呼び出しがかかるとここのコードが返されて、表示される。
重要な点としては、”TodoList.jsx"の記述の最後に"export default TodoList"という記述をしてどのファイルでも使えるようにエクスポートする必要がある。
反対に、コンポーネントを使用する側は、コードの一番上にインポートの記述をする必要がある。
App.jsで使用できるようにするためには、
import TodoList from './TodoList';
これを入力することで、先程までのエラーが解消され"が表示されるようになる。
このように、コンポーネントに分けることによってタブの名前に役割を入れることが出来て見やすくなる。さらに、コンポーネントごとに作成、管理、変更ができるため仕事の割り振りやコンポーネントごとの変更が容易であるという側面もあり開発にあたり非常に便利である。
反対に、変数を共有したりするのは少し煩雑になるので、コンポーネントを増やしすぎるのは良くない。
Todoアプリを作成するための機能を実装していく。
App.jsにおいて、
import './App.css';
import TodoList from './TodoList';
function App() {
return (
<>
<TodoList/>
<input type="text" />
<button>タスクを追加</button>
<button>完了したタスクの削除</button>
<div>残りのタスク:0</div>
</>
);
}
export default App;
このように追加する。
また、returnよりも下はJSXで記述されているため、一番上層の要素を並列化する事はできない。
そのため、並列化させたい場合空タグ(React.Fragment)で囲って記述する必要がある。
タスクを管理するために、useState()という機能を使用していく。
これはReact Hooksという機能の一部であるが詳しいことは知らないので次に調べてまとめる。軽く調べたら火傷しそうなので。
これを使用するためには1行目に"useState"をインポートしてやる必要がある。
import React, { useState } from "react";
useState()は変数を管理、監視するために使われる。
変数として"todos"を定める。これにタスクを要素として追加していき、名前(name)や、ID(id)、完了したかどうか(completed)などの属性を加えたオブジェクトを格納させる。
useState()を使用すると、"todos"に新たなタスクが追加されて変数に変更が起こったときにだけ、再レンダリングが行われる。
そして、"setTodos"は"todos"に要素を追加するときなどに起動して再定義するために使う。
const [todos, setTodos] = useState([]);
また、"todos"という変数のデータを”TodoList”と定めたコンポーネントで扱いたい。
そのときには、”TodoList"のタグの中でデータを引き渡す。この左に定めたtodosをpropsという。
以下の記述をすることでtodosという名前でこのコンポーネントに渡してくださいねという意味になる。右には右には渡したい変数の名前を入力すればよい。
<TodoList todos={todos} />
そして、TodoList側でpropsを受け取るには、コンポーネント内の最初の括弧()に好きなpropsの名前を記述する(この場合、props)。そして、その変数を使用したい箇所で"{props.todos}"とするとその変数に格納された値を使用することが出来る。
波括弧を記述することによって、JSXをであるからJavaScriptを記述することが出来る。
import React from 'react'
const TodoList = (props) => {
return (
<div>{props.todos}</div>
)
}
export default TodoList
App.js内のuseState()にデフォルト値を指定する。以下のようにリスト型にして"["Todo1", "Todo2"]"を追加してブラウザに表示する。
import React, { useState } from "react";
import TodoList from './TodoList';
function App() {
const [todos, setTodos] = useState(["Todo1", "Todo2"]);
return (
<>
<TodoList todos={todos} />
<input type="text" />
<button>タスクを追加</button>
<button>完了したタスクの削除</button>
<div>残りのタスク:0</div>
</>
);
}
export default App;
そして、一般的には波括弧で{todos}と渡してあげて使用する。その方が記述が少なく、わかりやすい。
import React from 'react'
const TodoList = ({ todos }) => {
return (
<div>{todos}</div>
)
}
export default TodoList
”TodoList”のコンポーネントは追加した”Todos”たちをリストのように格納している。すなわち、”Todo"というコンポーネントを複数格納しているコンポーネントであるということ。
よって、todosに格納されたタスクたちを1つずつ取り出して、表示する必要がある。そのために、map関数を利用して"todos"の要素を1つ取り出してTodoコンポーネントを記述していく。
return todos.map((todo) => (
<Todo todo={todo}/>
));
”TodoList.jsx"のファイルのreturnの中に上のような記述をすることで1つずつ要素を取り出して、その度に”Todo"というコンポーネントが起動するようになる。propsも設定しておく。
そして、srcディレクトリにTodo.jsxというファイルを作成し、”rafce"と記述してコンポーネントを作成する雛形を作成する。
受け取った”todo"の中身を表示するようにして、”TodoList.jsx"でTodoのコンポーネントをインポートする。
src/todo.jsx
import React from 'react'
const Todo = ({ todo }) => {
return (
<div>{todo}</div>
)
}
export default Todo
src/TodoList.jsx
import React from 'react';
import Todo from "./Todo";
const TodoList = ({ todos }) => {
return todos.map((todo) => (
<Todo todo={todo}/>
));
}
export default TodoList
こうすることで、ブラウザ上ではこのような表示になる。
少し分量が多くなったので後半は明日更新する。