iT邦幫忙

2022 iThome 鐵人賽

DAY 16
0
Modern Web

React應用記錄誌系列 第 16

Day16 實作練習-2 音樂列表

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20221001/20139800bE3BsbxctR.png

  1. configureStore

store.js

import {configureStore} from "@reduxjs/toolkit";
import notesReducer from '../features/notes/notesSlice';
import usersReducer  from '../features/users/usersSlice'

export const store = configureStore({
    reducer: {
       notes:notesReducer,
       users:usersReducer
    }
})

2.createSlice:

notesSlice.js

import { createSlice ,nanoid } from "@reduxjs/toolkit";
import {sub} from 'date-fns'
const initialState = [    
		{ id: 1, 
		  title: 'Skip the Small Talk',
		  content:'Lorem Ipsum is simply dummy text of the printing and ', 
		  date: sub(new Date(),{minutes:10}).toISOString()
		},
		{ id: 2, 
			title: ' We are All Runners ',
			content:'Lorem Ipsum is simply dummy text of the printing .', 
			date: sub(new Date(),{minutes:8}).toISOString()
		},
		{ id: 3, 
			title: 'Give Me Your Attention',
			content:'Lorem Ipsum is simply dummy text of the printingnd.', 
			date: sub(new Date(),{minutes:6}).toISOString()
		},
		{ id: 4, 
			title: 'Homesick Loving Caliber',
			content:'Lorem Ipsum is simply dummy text of the printing nd.', 
			date: sub(new Date(),{minutes:4}).toISOString()
		},
	]

const notesSlice = createSlice({
    name:'notes',
    initialState,
    reducers:{
		noteAdd:{
			reducer(state,action){
				   state.push(action.payload)
			    },
				prepare(title,content,userId){
					return{
						payload:{
							id:nanoid(),
							title,
							content,
							date: new Date().toISOString(),
							userId
						}
					}
				}
		}
			
	}
})

export const selectAllNotes = (state) => state.notes;
export const {noteAdd}= notesSlice.actions
export default notesSlice.reducer

usersSlice.js

import { createSlice } from "@reduxjs/toolkit";

const initialState = [
    { id: '0', name: 'Victor Lundberg' },
    { id: '1', name: 'Candelion' },
    { id: '2', name: ' Gamma Skies' }
]
const usersSlice = createSlice({
    name: 'users',
    initialState,
    reducers: {}
})
export const selectAllUsers = (state) => state.users;
export default usersSlice.reducer

3.component

NotesUser.js

import { useSelector } from "react-redux";
import { selectAllUsers } from "../users/usersSlice";
import React from 'react'
const NotesUser = (userId) => {
        
        const users = useSelector(selectAllUsers)
        const writer = users.find(user => user.id === userId);
       return <span>by {writer ? writer.name : 'Unknown writer'}</span>
    }

export default NotesUser

Time.js

import { parseISO, formatDistanceToNow } from 'date-fns';

const Time = ({ timestamp }) => {
    let time = ''
    if (timestamp) {
        const date = parseISO(timestamp)
        const timePeriod = formatDistanceToNow(date)
        time = `${timePeriod} ago`
    }
    return (
        <span title={timestamp}>
            &nbsp; <i>{time}</i>
        </span>
    )
}
export default Time

NotesLis.js

import { useSelector } from "react-redux";
import {selectAllNotes} from './notesSlice';
import NotesUser from './NotesUser';
import Time from './Time';

const NotesList = () => {
   const notes = useSelector(selectAllNotes)
  const allNotes = notes.map(note =>(
        <div className="note" key={note.id}>
            <h4>{note.title}</h4>
            <p>{note.content.substring(0,150)}</p> 
            <p><NotesUser userId={note.user}/></p>                     
            <p><Time timestamp={note.date} /></p>                     
        </div>
    ))
  return (
    <div  className="container">
      <div className ="box">
         <h1>Music Playlist </h1>
         <div className="note-list">{allNotes}</div>
       </div>
    </div>
  )
}

export default NotesList

NotesForm.js


import { useState } from "react";
import { useDispatch,useSelector} from "react-redux";
import { noteAdd } from "./notesSlice";
import { selectAllUsers } from "../users/usersSlice";

const NotesForm = () => {
    const dispatch = useDispatch()
    const [title, setTitle] = useState('')
    const [content, setContent] = useState('')       
    const [usersId, setUsersId] = useState('')    
    const users = useSelector(selectAllUsers)

    const onTitleChanged = e => setTitle(e.target.value)
    const onContentChanged = e => setContent(e.target.value)
    const onUsersChanged = e => setUsersId(e.target.value)

    const onSaveNoteClick =()=>{
        if (title && content){
            dispatch(
                noteAdd(title,content,usersId) 
            )
            setTitle('')
            setContent('')
        }
    }
    const usersOptions = users.map(user => (
        <option key={user.id} value={user.id}>
            {user.name}
        </option>
    ))
       
    return (
        <div >
            <h3>Add a New Music</h3>
            <form className="note new">
                <label htmlFor="postTitle">Song</label>
                <input
                    type="text"
                    id="postTitle"
                    name="postTitle"
                    value={title}
                    onChange={onTitleChanged}
                />

               <label htmlFor="postUser">Artist</label>
                <select id="postAuthor" value={usersId} onChange={onUsersChanged}>
                    <option value=""></option>
                    {usersOptions}
                </select>              
                
                <label htmlFor="postContent">album</label>
                <textarea
                    id="postContent"
                    name="postContent"
                    value={content}
                    onChange={onContentChanged}
                />
                <button
                    type="button"                    
                    onClick={onSaveNoteClick}                    
                >Save Music</button>
            </form>
        </div>
    )
}
export default NotesForm
                   

上一篇
Day15實作練習 用Redux Toolkit做學習筆記列表
下一篇
Day17 Tailwind CSS安裝與設定(for HTML)
系列文
React應用記錄誌31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言