React( ReduxToolkit )の構成でアプリを作成をしました【Bulletin board App】

## 環境の準備
①ターミナルでreactアプリケーションを作成する。

```
npx create-react-app <プロジェクト名> --template redux
cd <プロジェクト名>
yarn start
```
② 必要なパッケージをインストールする。

```
npm install @reduxjs/toolkit react-redux
```

## コンポーネント・ファイル構成

```
  src
   ├─ features
        └── Posts.js
   ├── App.css
   ├── App.js
   ├── DummyData.js
   └── index.js
```
```src / features / Posts.js
import { createSlice } from '@reduxjs/toolkit';
import { PostsData } from '../DummyData';

export const postSlice = createSlice({
  name: 'posts',
  initialState: { value: PostsData },
  reducers: {
    addPost: (state, action) => {
      state.value.push(action.payload);
    },
    deletePost: (state, action) => {
      state.value = state.value.filter((post) => post.id !== action.payload.id);
    },
  },
});
export const { addPost, deletePost } = postSlice.actions;
export default postSlice.reducer;
```
```src/App.css
.App {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 1.5rem;
  height: 100vh;
}

.App h1 {
  font-size: 2.5rem;
}

hr {
  margin-top: 20px;
  margin-bottom: 0;
}

.displayPosts .post {
  margin-top: 30px;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
  padding: 20px 30px;
  border-radius: 10px;
  min-width: 500px;
  background-color: white;
}

.displayPosts .postName {
  font-size: 25px;
  margin-top: 6px;
}

.displayPosts .postContent {
  margin-top: -10px;
  font-size: 15px;
  font-weight: 400;
}

input {
  padding: 10px 20px;
  margin-right: 10px;
  border: none;
  box-shadow: 0 1px 3px 0 rgba(123, 123, 123, 0.1),
    0 6px 20px 0 rgba(118, 118, 118, 0.19);
  outline: none;
}

button {
  padding: 7px 30px;
  border: none;
  border-radius: 4px;
  box-shadow: 0 1px 3px 0 rgba(123, 123, 123, 0.1),
    0 6px 20px 0 rgba(55, 55, 55, 0.19);
  background-color: royalblue;
  color: white;
  cursor: pointer;
}

```
```src/App.js
import './App.css';
import { useSelector, useDispatch } from 'react-redux';
import { addPost, deletePost } from './features/Posts';
import { useState } from 'react';

function App() {
  const [name, setName] = useState('');
  const [content, setContent] = useState('');

  //useSelectorでstoreの中のstateにアクセスできる。usersはreducer名
  const postList = useSelector((state) => state.posts.value);
  const dispatch = useDispatch();

  const handleClick = () => {
    dispatch(
      addPost({
        id: postList.length + 1,
        name: name,
        content: content,
      })
    );

    setName('');
    setContent('');
  };
  return (
    <div className='App'>
      <div>
        <h1>React-Redux掲示板</h1>
      </div>
      <div className='addPost'>
        <input
          type='text'
          placeholder='お名前'
          onChange={(e) => setName(e.target.value)}
          value={name}
        />
        <input
          type='text'
          placeholder='投稿内容'
          onChange={(e) => setContent(e.target.value)}
          value={content}
        />
        <button onClick={() => handleClick()}>投稿</button>
        <hr />
      </div>
      <div className='displayPosts'>
        {postList.map((post) => (
          <div key={post.id} className='post'>
            <h1 className='postName'>{post.name}</h1>
            <h1 className='postContent'>{post.content}</h1>
            <button onClick={() => dispatch(deletePost({ id: post.id }))}>
              削除
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}

export default App;
```
```src / DummyData.js
export const PostsData = [
  {
    id: 1,
    name: 'ShinCode',
    content: 'Redux勉強なう',
  },
  {
    id: 2,
    name: '名無しさん',
    content: 'ShinCodeさん分かりやすい',
  },
  {
    id: 3,
    name: '駆け出しエンジニア',
    content: 'Udemy受講してみようかな',
  },
  {
    id: 4,
    name: 'スタックオーバーフローさん',
    content: 'エンジニアのスタバ',
  },
];
```
```src / index.css
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background-color: lightyellow;
}
code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}
```
```src / index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
import postsReducer from './features/Posts';

const store = configureStore({
  reducer: {
    posts: postsReducer,
  },
});

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

```

## 参考サイト
[ReactとReduxを使って掲示板アプリを構築してみよう【Redux Toolkit実践】](https://www.youtube.com/watch?v=p4oHHzqjRMg&t=260s)