Reactのコードを簡潔に書くためのTips7選

## 新しい状態が前の状態に依存する時の更新に気をつける

新しい状態が前の状態に依存している場合は、常に前の状態の関数として状態を設定することをお勧めします。 状態の更新は非同期処理のため、バッチ処理される可能性があり、この方法で更新を書き込まないと、予期しない結果が生じる可能性があります。

### BadExample
```jsx
import React, { useState } from "react";
export const App = () => {
  const [isDisabled, setIsDisabled] = useState(false);
  const toggleButton = () => {
    setIsDisabled(!isDisabled);
  };
  // here toggling twice will yeild the same result
  // as toggling once
  const toggleButtonTwice = () => {
    toggleButton();
    toggleButton();
  };
  return (
    <div>
      <button disabled={isDisabled}>
        I'm {isDisabled ? "disabled" : "enabled"}
      </button>
      <button onClick={toggleButton}>
        Toggle button state
      </button>
      <button onClick={toggleButtonTwice}>
        Toggle button state 2 times
      </button>
    </div>
  );
};
```

### GoodExample
```jsx
import React, { useState } from "react";
export const App = () => {
  const [isDisabled, setIsDisabled] = useState(false);
  const toggleButton = () => {
    setIsDisabled((isDisabled) => !isDisabled);
  };
  const toggleButtonTwice = () => {
    toggleButton();
    toggleButton();
  };
  return (
    <div>
      <button disabled={isDisabled}>
        I'm {isDisabled ? "disabled" : "enabled"}
      </button>
      <button onClick={toggleButton}>
        Toggle button state
      </button>
      <button onClick={toggleButtonTwice}>
        Toggle button state 2 times
      </button>
    </div>
  );
};
```

## コンポーネントをきれいに見やすくする

### BadExample
```jsx
// src/App.tsx
export default function App() {
  const posts = [
    {
      id: 1,
      title: "How to write clean react code",
    },
    {
      id: 2,
      title: "Eat, sleep, code, repeat",
    },
  ];
  return (
    <main>
      <nav>
        <h1>App</h1>
      </nav>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>
            {post.title}
          </li>
        ))}
      </ul>
    </main>
  );
}
```

### GoodExample
```jsx
// src/App.tsx
export default function App() {
  return (
    <main>
      <Navigation title="App" />
      <Posts />
    </main>
  );
}
// src/components/Navigation.tsx
type NavigationProps {
  title: string;
}
export default function Navigation({ title }: NavigationProps) {
  return (
    <nav>
      <h1>{title}</h1>
    </nav>
  );
}
// src/components/Posts.tsx
export default function Posts() {
  const posts = [
    {
      id: 1,
      title: "How to write clean react code",
    },
    {
      id: 2,
      title: "Eat, sleep, code, repeat",
    },
  ];
  return (
    <ul>
      {posts.map((post) => (
        <Post key={post.id} title={post.title} />
      ))}
    </ul>
  );
}
// src/components/Post.tsx
type PostProps {
  title: string;
}
export default function Post({ title }: PostProps) {
  return <li>{title}</li>;
}
```

## 複数の状態を持つものは定数や列挙型を使う

### BadExample
```jsx
import React, { useState } from "react";
export const App = () => {
  const [status, setStatus] = useState("Pending");
  return (
    <div>
      <p>{status}</p>
      <button onClick={() => setStatus("Pending")}>
        Pending
      </button>
      <button onClick={() => setStatus("Success")}>
        Success
      </button>
      <button onClick={() => setStatus("Error")}>
        Error
      </button>
    </div>
  );
};
```

### GoodExample
```jsx
import React, { useState } from "react";
enum Status {
  Pending = "Pending",
  Success = "Success",
  Error = "Error",
}
// OR
// const Status = {
//   Pending: "Pending",
//   Success: "Success",
//   Error: "Error",
// } as const;
export const App = () => {
  const [status, setStatus] = useState(Status.Pending);
  return (
    <div>
      <p>{status}</p>
      <button onClick={() => setStatus(Status.Pending)}>
        Pending
      </button>
      <button onClick={() => setStatus(Status.Success)}>
        Success
      </button>
      <button onClick={() => setStatus(Status.Error)}>
        Error
      </button>
    </div>
  );
};
```

## できるだけTSXの中を簡潔にする

### BadExample
```jsx
const App = () => {
  return (
    <div>
      <button
        onClick={() => {
          // ...
        }}
      >
        Toggle Dark Mode
      </button>
    </div>
  );
};
```

### GoodExample
```jsx
const App = () => {
  const handleDarkModeToggle = () => {
    // ...
  };
  return (
    <div>
      <button onClick={handleDarkModeToggle}>
        Toggle Dark Mode
      </button>
    </div>
  );
};
```

## 省略記法を使う
### BadExample
```jsx
type TextFieldProps {
  fullWidth: boolean;
}
const TextField = ({ fullWidth }: TextFieldProps) => {
  // ...
};
const App = () => {
  return <TextField fullWidth={true} />;
};
```

### GoodExample
```jsx
type TextFieldProps {
  fullWidth: boolean;
}
const TextField = ({ fullWidth }: TextFieldProps) => {
  // ...
};
const App = () => {
  return <TextField fullWidth />;
};
```

## string型のpropsに波括弧は不要
### BadExample
```jsx
type AvatarProps {
  username: string;
}
const Avatar = ({ username }: AvatarProps) => {
  // ...
};
const Profile = () => {
  return <Avatar username={"John Wick"} />;
};
```

### GoodExample
```jsx
type AvatarProps {
  username: string;
}
const Avatar = ({ username }: AvatarProps) => {
  // ...
};
const Profile = () => {
  return <Avatar username="John Wick" />;
};
```

## 不必要なindexは使用しない

### BadExample
```jsx
{todos.map((todo, index) =>
  <Todo
    {...todo}
    key={index}
  />
)}
```
### GoodExample
```jsx
{todos.map(todo => (
  <Todo
    {...todo}
    key={todo.id}
  />
))}
```

## 参考
https://tapajyoti-bose.medium.com/7-tips-for-clean-react-typescript-code-you-must-know-3ebd34af343f