# JS 的奇幻旅程 <br>
## Tic-Tac-Toe
[TOC]
----
Made by FanRende (030Mortal#5525)
<img src="https://i.imgur.com/ApP0azJ.png" width="50%">
---
## Tutorial
基本上是跟著這個教學走
[Tutorial: Tic-Tac-Toe *React](https://beta.reactjs.org/learn/tutorial-tic-tac-toe)
----
### 開發環境
在 Arch Linux 的一個 distribution Manjaro 上開發
Local 時使用 VSCode 及 terminal
Remote 時使用 [Code Server](https://github.com/coder/code-server)
搭配 ssh forward local port
----
### Build Tool
使用了之前介紹的 Vite 來作為 Module Bundler
----
### 結果
<img src="https://i.imgur.com/7hbyZei.png" width="75%">
---
## React.JS 基本概念
- Component & Props
- JSX
- State
----
### Component & Props
將一整個 UI 切分成很多塊 Component
並且每個 Component 可能還有自己的子 Component
<div class="flex-container">
<div class="flex-content">
<img src="https://i.imgur.com/jMCbmTP.png" width="100%">
</div>
<div class="flex-content" style="font-size: 0.5em">
1. **FilterableProductTable (grey)** contains the entire app.
1. **SearchBar (blue)** receives the user input.
1. **ProductTable (lavender)** displays and filters the list according to the user input.
1. **ProductCategoryRow (green)** displays a heading for each category.
1. **ProductRow (yellow)** displays a row for each product.
</div>
</div>
----
### JSX
`Square` Component in Tic-Tac-Toe
```jsx
function Square({ value, onSquareClick }) {
return (
<button className="square" onClick={onSquareClick}>
{value}
</button>
);
}
```
----
#### Conditional Rendering
利用 Javascript 的流程控制 控制組件渲染的時機
```jsx
function AdminPanel({ isAdmin }) {
if(!isAdmin)
return;
return <span>Admin</span>;
}
```
----
### State
如果一個參數需要在多個元件間共用
React 中可以使用 state
```jsx
import { useState } from 'react';
function IndexPanel() {
const [index, setIndex] = useState(0);
function handleClick() {
setIndex(index + 1);
}
return <button onclick={handleClick}>{index}</button>
}
```
----
#### Proper props for set state
```jsx
import { useState } from 'react';
function IndexButton({index, onIndexChange}) {
return <button onclick={onIndexChange}>next</button>
}
function IndexPanel() {
const [index, setIndex] = useState(0);
function handleClick() {
setIndex(index + 1);
}
return (
<>
<IndexButton index={index} onIndexChange={handleClick} />
<span>{index}</span>
</>
);
}
```
</div>
</div>
----
#### simply replace state may cause problems
React update state during next render
before the render, state value is the same
<div class="flex-container">
<div class="flex-content">
e.g.
</div>
<div class="flex-content">
```jsx
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}>+3</button>
</>
)
}
```
</div>
<div class="flex-content">
```javascript
// frame 0
"number is 0"
setNumber(0 + 1);
setNumber(0 + 1);
setNumber(0 + 1);
// frame 1
"number becomes 1"
"number becomes 1"
"number becomes 1"
```
</div>
</div>
----
you should use an **updater function** to update state
<div class="flex-container">
<div class="flex-content">
```jsx
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number => number + 1);
setNumber(number => number + 1);
setNumber(number => number + 1);
}}>+3</button>
</>
)
}
```
</div>
<div class="flex-content">
```jsx
// frame 0
"number is 0"
setNumber(number => number + 1);
setNumber(number => number + 1);
setNumber(number => number + 1);
// frame 1
"number becomes number + 1 = 1"
"number becomes number + 1 = 2"
"number becomes number + 1 = 3"
```
</div>
</div>
---
參考 / 延伸閱讀:
- [React Docs BETA](https://beta.reactjs.org/)
<style>
.gray {
color: gray;
font-size: 0.5em;
}
.json, .jsx {
font-size: 0.75em !important;
line-height: 1.2em !important;
}
.mermaid {
background-color: rgba(0, 0, 0, 0) !important;
}
.flex-container {
display: flex;
justify-content: center;
}
.flex-content {
flex-grow: 1;
}
</style>
<style>
/* Customize website's scrollbar like Mac OS */
::-webkit-scrollbar {
-webkit-appearance: none;
width: 7px;
}
::-webkit-scrollbar-thumb {
border-radius: 4px;
background-color: rgba(128, 128, 128, 1);
-webkit-box-shadow: 0 0 1px rgba(255, 255, 255, .5);
}
</style>
{"metaMigratedAt":"2023-06-17T19:25:23.397Z","metaMigratedFrom":"YAML","title":"JS 的奇幻旅程 Tic-Tac-Toe","breaks":true,"description":"Tic-Tac-Toe in ReactJS Tutorial","slideOptions":"{\"theme\":\"solarized\",\"transition\":\"fade\",\"previewLinks\":true}","contributors":"[{\"id\":\"82f6b599-31b8-4112-9dc5-7d7b7d6a3ebb\",\"add\":6900,\"del\":1986}]"}