diff --git a/react_webgame/7. 틱택토/Table.jsx b/react_webgame/7. 틱택토/Table.jsx
new file mode 100644
index 00000000..14d4c1dc
--- /dev/null
+++ b/react_webgame/7. 틱택토/Table.jsx
@@ -0,0 +1,17 @@
+import React, {memo} from "react";
+import Tr from "./Tr";
+
+const Table = memo(({ tableData, dispatch }) => {
+ console.log("table rendered");
+ return (
+
+ {Array(tableData.length)
+ .fill()
+ .map((tr, i) => (
+
+ ))}
+
+ );
+});
+
+export default Table;
diff --git a/react_webgame/7. 틱택토/Td.jsx b/react_webgame/7. 틱택토/Td.jsx
new file mode 100644
index 00000000..5133653b
--- /dev/null
+++ b/react_webgame/7. 틱택토/Td.jsx
@@ -0,0 +1,24 @@
+import React, { useCallback, useRef, useEffect, memo } from "react";
+import { CLICK_CELL } from "./TicTacToe";
+
+const Td = memo(({ rowIndex, cellIndex, dispatch, cellData }) => {
+ console.log("td rendered")
+
+ const ref = useRef([]);
+ useEffect(() => {
+ console.log(rowIndex === ref.current[0], cellIndex === ref.current[1], dispatch === ref.current[2], cellData === ref.current[3])
+ ref.current = [rowIndex, cellIndex, dispatch, cellData]
+ }, [rowIndex, cellIndex, dispatch, cellData])
+
+ const onClickTd = useCallback(() => {
+ console.log(rowIndex, cellIndex);
+ if(cellData) {
+ return;
+ }
+ dispatch({ type: CLICK_CELL, row: rowIndex, cell: cellIndex });
+ }, [cellData]);
+
+ return {cellData} | ;
+});
+
+export default Td;
diff --git a/react_webgame/main/TicTacToe.jsx b/react_webgame/7. 틱택토/TicTacToe.jsx
similarity index 100%
rename from react_webgame/main/TicTacToe.jsx
rename to react_webgame/7. 틱택토/TicTacToe.jsx
diff --git a/react_webgame/7. 틱택토/Tr.jsx b/react_webgame/7. 틱택토/Tr.jsx
new file mode 100644
index 00000000..4ef97e7d
--- /dev/null
+++ b/react_webgame/7. 틱택토/Tr.jsx
@@ -0,0 +1,20 @@
+import React, {memo, useMemo} from "react";
+import Td from "./Td";
+
+const Tr = memo(({ rowData, rowIndex, dispatch }) => {
+ console.log("tr rendered")
+ return (
+
+ {Array(rowData.length)
+ .fill()
+ .map((td, i) => (
+ useMemo(
+ () => | {""} | ,
+ [rowData[i]],
+ )
+ ))}
+
+ );
+});
+
+export default Tr;
diff --git a/react_webgame/7. 틱택토/client.jsx b/react_webgame/7. 틱택토/client.jsx
new file mode 100644
index 00000000..7ffc6a03
--- /dev/null
+++ b/react_webgame/7. 틱택토/client.jsx
@@ -0,0 +1,6 @@
+import React from "react";
+import ReactDom from "react-dom";
+
+import TicTacToe from "./TicTacToe";
+
+ReactDom.render(, document.querySelector("#root"));
diff --git a/react_webgame/7. 틱택토/index.html b/react_webgame/7. 틱택토/index.html
new file mode 100644
index 00000000..e74ccd6f
--- /dev/null
+++ b/react_webgame/7. 틱택토/index.html
@@ -0,0 +1,21 @@
+
+
+
+ 틱택토
+
+
+
+
+
+
+
diff --git a/react_webgame/main/Form.jsx b/react_webgame/main/Form.jsx
new file mode 100644
index 00000000..959bc87d
--- /dev/null
+++ b/react_webgame/main/Form.jsx
@@ -0,0 +1,43 @@
+import React, { useState, useCallback } from "react";
+
+const Form = () => {
+ const [row, setRow] = useState(10);
+ const [cell, setCell] = useState(10);
+ const [mine, setMine] = useState(20);
+
+ const onChangeRow = useCallback((e) => {
+ setRow(e.target.value);
+ }, []);
+ const onChangeCell = useCallback((e) => {
+ setCell(e.target.value);
+ }, []);
+ const onChangeMine = useCallback((e) => {
+ setMine(e.target.value);
+ }, []);
+
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default Form;
diff --git a/react_webgame/main/MineSearch.jsx b/react_webgame/main/MineSearch.jsx
new file mode 100644
index 00000000..f73e4269
--- /dev/null
+++ b/react_webgame/main/MineSearch.jsx
@@ -0,0 +1,30 @@
+import React, { useReducer } from "react";
+import Table from "./Table";
+
+const initialState = {
+ tableData: [],
+ timer: 0,
+ result: "",
+};
+
+const reducer = (state, action) => {
+ switch (action.type) {
+ default:
+ return state;
+ }
+};
+
+const MineSearch = () => {
+ const [state, dispatch] = useReducer(reducer, initialState);
+ const { result } = state;
+ return (
+ <>
+
+ {timer}
+
+ {result}
+ >
+ );
+};
+
+export default MineSearch;