[ToyProject-Todomate] ํˆฌ๋‘๋ฉ”์ดํŠธ ํด๋ก  ํ”„๋กœ์ ํŠธ 36

2022. 2. 8. 15:45ใ†WEB Dev/ToyProject

728x90


๐Ÿ”ท CloneTodo โ˜‘ - Todomate Clone Project  |  Team CloneMate

 

CloneTodo : ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์‚ฌ๋ž‘ํ•˜๋Š” ํˆฌ๋‘๋ฉ”์ดํŠธ๋ฅผ ํด๋ก ํ•˜์—ฌ ์›น ์„œ๋น„์Šค๋ฅผ ๋ฐฐํฌํ•ด๋ณด๋Š” ํ”„๋กœ์ ํŠธ

 


 

 

 

 

728x90

 

 

1. ํ•  ์ผ ํด๋ฆญ ์‹œ ๋“ฑ์žฅ ๋ชจ๋‹ฌ

 

์ด์ œ ๋ฟŒ๋ ค์ง„ ํ•  ์ผ์„ ํด๋ฆญํ•˜๋ฉด 5๊ฐœ์˜ ๋ฒ„ํŠผ์ด ์žˆ๋Š” ๋ชจ๋‹ฌ์ฐฝ์„ ๋„์›Œ์•ผ ํ•œ๋‹ค.

์ด ๋ชจ๋‹ฌ์€ ํ•ด๋‹น ํ•  ์ผ์˜ ์ •๋ณด๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ํ•œ๋‹ค.

๋ชฉํ‘œ ์„ค์ •ํ•  ๋•Œ ์ผ๋˜ MUI Dialog UI๋ฅผ ์“ธ๊นŒ๋„ ์ƒ๊ฐํ–ˆ๋Š”๋ฐ ๋‹จ์ˆœํ•œ ๋ฒ„ํŠผ๋งŒ ์žˆ์œผ๋ฉด ๋˜์–ด์„œ ์ด๋ฒˆ์—๋Š” Modal์„ ์ ์šฉํ•ด๋ณด์•˜๋‹ค. 

 

์›๋ณธ๊ณผ ๋น„์Šทํ•œ ์‚ฌ์ด์ฆˆ๋กœ ๋ชจ๋‹ฌ์˜ ์ปจํ…Œ์ด๋„ˆ์™€ ๋ฒ„ํŠผ์„ ๊ตฌํ˜„ํ–ˆ๋‹ค.

 

 

{/* ๋ชจ๋‹ฌ ์ƒ์„ฑ */}
<TodoModal 
modalOpen={modalOpen} handleTodoModalClose={handleTodoModalClose}s
electedTodo={selectedTodo} 
clickTodoEditHandler={clickTodoEditHandler} 
clickTodoDeleteHandler={clickTodoDeleteHandler}  />

 

export function TodoModal (props) {

    const modalOpen = props.modalOpen;
    const handleTodoModalClose = props.handleTodoModalClose;
    const selectedTodo = props.selectedTodo;
    const clickTodoEditHandler = props.clickTodoEditHandler;
    const selectedInputIndex = props.selectedInputIndex;
    const clickTodoDeleteHandler = props.clickTodoDeleteHandler;

    return(
        <Modal open={modalOpen}
        onClose={handleTodoModalClose}
        aria-labelledby="modal-modal-title"
        aria-describedby="modal-modal-description"
        className="feed-todo-modal-box"
         >
            <Box className="feed-todo-modal-wrap" >
                <p className="feed-todo-modal-head">{selectedTodo.title}</p>
                <Box className="feed-todo-modal-icon-wrap">
                    <button className="feed-todo-edit-icon" onClick={clickTodoEditHandler} data-index={selectedInputIndex} ><EditIcon className="feed-modal-icon" /><span>์ˆ˜์ •</span></button>
                    <button className="feed-todo-delay-icon" data-index={selectedInputIndex} ><SkipNextIcon className="feed-modal-icon" /><span>๋‚ด์ผ ํ•˜๊ธฐ</span></button>
                    <button className="feed-todo-date-change-icon" data-index={selectedInputIndex} ><SyncAltIcon className="feed-modal-icon" /><span>๋‚ ์งœ ๋ฐ”๊พธ๊ธฐ</span></button>
                    <button className="feed-todo-order-change-icon" data-index={selectedInputIndex} ><WrapTextIcon className="feed-modal-icon" /><span>์ˆœ์„œ ๋ณ€๊ฒฝ</span></button>
                    <button className="feed-todo-delete-icon" data-index={selectedInputIndex} ><DeleteOutlineIcon className="feed-modal-icon" onClick={clickTodoDeleteHandler} data-index={selectedInputIndex} /><span>์‚ญ์ œ</span></button>
                </Box>
            </Box>
        </Modal>  
    )
}

 

 

 

๋ชจ๋‹ฌ์„ on/off ํ•˜๊ณ  ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๋“ค์€ ๊ตณ์ด atom์— ๋„ฃ์ง€ ์•Š์•„๋„ ๋  ๊ฒƒ ๊ฐ™์•„์„œ props๋กœ ์ „๋‹ฌํ–ˆ๋‹ค.

 

๋ชจ๋‹ฌ์€ ์ด๋ฏธ MUI์—์„œ ๋‚ด๋ถ€ ์ด๋ฒคํŠธ๊ฐ€ ๋‹ค ๊ตฌํ˜„์ด ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— madalOpen ์ด๋ผ๋Š” props์— true, false ๋ถˆ๋ฆฌ์–ธ ๊ฐ’๋งŒ ์ ์šฉํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ํ•ด๋‹น ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

 

/* ๋ชจ๋‹ฌ ๊ด€๋ จ */

//ํˆฌ๋‘ ํด๋ฆญ ์‹œ ๋ชจ๋‹ฌ ๋“ฑ์žฅ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
const clickTodoModalHandler = (e) => {
    // console.log("click index", e.currentTarget.dataset.key)
    let todoIndex = e.currentTarget.dataset.key;
    handleTodoModalOpen()
    setSelectedTodo(selectedTodo = todo[todoIndex])
    setSelectedInputIndex(todoIndex);
}

// ํˆฌ๋‘ ํด๋ฆญ์‹œ ๋ชจ๋‹ฌ ๋…ธ์ถœ on off
const handleTodoModalOpen = () => setModalOpen(true);
const handleTodoModalClose = () => setModalOpen(false);

 

 

todo ๊ฐ’์— ๋งž๋Š” index๋ฅผ ์–ป์–ด๋‚ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— dataset ์„ ์ด์šฉํ–ˆ๋‹ค.

todo.map ์œผ๋กœ ๋ฟŒ๋ฆฌ๊ณ  ์žˆ๋Š” <input> ํƒœ๊ทธ์— (์ด์ „๊นŒ์ง€๋Š” InputBase MUI ๋ฅผ ์ด์šฉํ–ˆ๋Š”๋ฐ, readOnly ์„ค์ •์ด ์ž˜ ์•ˆ๋จนํ˜€์„œ HTML ๊ธฐ๋ณธ ํƒœ๊ทธ์ธ input์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ๋‹ค.)

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๊ณ  data-index ๋˜ํ•œ ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์„œ e.target์— ๋‹ด๊ฒจ ์˜ค๋„๋ก ํ–ˆ๋‹ค.

 

 

 

โ€ป data-oo ์†์„ฑ์œผ๋กœ ์ •๋ณด ์‚ฌ์šฉํ•˜๊ธฐ

 

ํ˜„์žฌ map์œผ๋กœ index๋ฅผ ๋ฟŒ๋ ค์ค„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ input ํƒœ๊ทธ์— data ์ ‘๋‘์‚ฌ๋ฅผ ์ด์šฉํ•ด ์ •๋ณด๋ฅผ ๋‹ด์•„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฐ data ์ ‘๋‘์‚ฌ๋ฅผ dataset ์ด๋ผ๊ณ  ํ•˜๋Š”๋ฐ 

<element data-item="itisdata"></element> ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•œ ๋‹ค์Œ

onclick์ด๋‚˜ onchange ๋“ฑ ์ •๋ณด ๋ณ€๊ฒฝ์„ ์บ์น˜ํ•  ์ˆ˜ ์žˆ๋Š” ์ด๋ฒคํŠธ ํ•จ์ˆ˜๋“ค์—์„œ ์‚ฌ์šฉํ•  ๋•Œ๋Š”

e.target.dataset.item ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋•Œ๋Š” "itisdata"๊ฐ€ ๋„˜์–ด์˜ค๊ฒŒ ๋œ๋‹ค.

 

์ด data-index๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹นํ•˜๋Š” ์ •๋ณด๋ฅผ ์ „๋ถ€ ๋ชจ๋‹ฌ์— ์ „๋‹ฌํ•  ์ˆ˜๊ฐ€ ์žˆ์—ˆ๋‹ค.

๋Œ€์‹  todo ์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฝ‘์•„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํด๋ฆญํ•˜๋ฉด selectedTodo๋ผ๋Š” state๋ฅผ ์ƒ์„ฑํ•ด ํด๋ฆญํ•œ ์ •๋ณด๊ฐ’์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค. 

 

 

 

 

 

ํ•  ์ผ ์ˆ˜์ • ๋ชจ๋‹ฌ ๊ธฐ๋Šฅ 

 

1. ์ˆ˜์ •

์„ ํƒํ•œ index์˜ todo input ๋ถ€๋ถ„์˜ readOnly ์ƒํƒœ ๋ณ€๊ฒฝ ํ›„ ๋ฐ›์•„์˜จ todo State๋ฅผ ์ˆ˜์ •ํ•ด์„œ ๋‹ค์‹œ recoil์— ๋ฐ˜์˜

 

2. ๋‚ ์งœ๋ฐ”๊พธ๊ธฐ

ํ•ด๋‹น todo State์˜ date ๊ฐ’์„ ๋ณ€๊ฒฝ ํ•ด ์ค€๋‹ค.

 

3. ์˜ค๋Š˜ ํ•˜๊ธฐ

ํ•ด๋‹น todo State์˜ date ๊ฐ’์„ ์˜ค๋Š˜๋กœ ๋ณ€๊ฒฝ

 

4. ์ˆœ์„œ ๋ณ€๊ฒฝ

ํ•ด๋‹น ๋‚ ์งœ์˜ todo state๋ฅผ ๋ณ„๋„์˜ ์ปดํฌ๋„ŒํŠธ (ํŽ˜์ด์ง€) ๋กœ ์ด๋™์‹œ์ผœ์„œ ๋“œ๋ž˜๊ทธ๋กœ order ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

์Œ... drag ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์จ์•ผ๊ฒ ์ง€?

 

5. ์‚ญ์ œ

์„ ํƒํ•œ index์˜ todo๋ฅผ ์‚ญ์ œํ•ด recoil์— ๋ฐ˜์˜

 

์ตœ์ข…  ์ˆ˜์ •๋œ recoil todo state๋Š” ํŽ˜์ด์ง€ ๋ฒ—์–ด๋‚  ๋•Œ api๋ฅผ ํ†ตํ•ด ์—…๋ฐ์ดํŠธ ์‹œํ‚ค๋„๋ก ํ•œ๋‹ค.

 

 

 

 

 

2. ์ˆ˜์ • / ์‚ญ์ œ ๊ธฐ๋Šฅ

 

๋ชจ๋‹ฌ์—์„œ ์ˆ˜์ • ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด input์˜ readonly ์†์„ฑ์ด true์—์„œ false๋กœ ๋ณ€ํ•ด์•ผ ํ•œ๋‹ค.

readonly ์†์„ฑ์„ ์ฃผ๋Š” ์ด์œ ๋Š” '์ˆ˜์ •' ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ฉด input ์ž์ฒด๊ฐ€ list์˜ ๊ธฐ๋Šฅ๋„ ํ•จ๊ป˜ ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

readonly๋Š” ๊ทธ์•ผ๋ง๋กœ '์ฝ๊ธฐ์ „์šฉ' ์ƒํƒœ๋ผ ์ฝ๊ธฐ ์ „์šฉ์ด๋ฉด ์“ฐ๊ธฐ๊ฐ€ ์•ˆ๋˜๋‹ˆ true ์ƒํƒœ๋ฉด ์“ฐ๊ธฐ๋ฅผ ํ•  ์ˆ˜ ์—†๊ณ  false๋ฉด ์“ฐ๊ธฐ๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

MUI์˜ InputBase์—์„œ๋„ readonly๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์ƒํƒœ๊ฐ’์„ ๋ฐ”๊ฟ”๋„ ์ ์šฉ์ด ์•ˆ๋˜์–ด์„œ input์„ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

๋Œ€์‹  CSS์˜ border์™€ outline ์„ 0์œผ๋กœ ์ˆ˜์ •ํ•ด์„œ ์ž‘์„ฑํ•˜์ง€ ์•Š์„ ๋•Œ๋Š” ๋ฆฌ์ŠคํŠธ์ฒ˜๋Ÿผ ๋ณด์ด๋„๋ก ํ–ˆ๋‹ค.

 

 

์ˆ˜์ • ๊ธฐ๋Šฅ

 

์ˆ˜์ •์ด ์ข€ ๊ณ ๋‚œ์ด๋„์˜€๋Š”๋ฐ readonly ์†์„ฑ์ด ์ž˜ ์•ˆ๋ฐ”๋€Œ์–ด์„œ ํ•ด๊ฒฐํ•˜๋Š๋ผ๊ณ  ์ดํ‹€์„ ์†Œ๋น„ํ–ˆ๋‹ค. InputBase๋ฅผ ํฌ๊ธฐํ•˜๋Š” ๊ฒƒ์œผ๋กœ ํ•˜๊ณ  input์œผ๋กœ ๋ฐ”๊พธ๋‹ˆ ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํžˆ ํ•ด๊ฒฐ์ด ๋˜๋Š”๊ฑธ...!

 

์ˆ˜์ • ๋˜ํ•œ ํด๋ฆญํ•œ ํ•  ์ผ๋งŒ readonly๊ฐ€ false๊ฐ€ ๋˜์–ด์•ผ ํ•ด์„œ ๋ชฉํ‘œ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๊ตฌํ˜„ํ–ˆ ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ–ˆ๋‹ค.

์›๋ž˜ todo์˜ readonly ์†์„ฑ๋„ recoil๋กœ ๊ด€๋ฆฌํ•˜๋ ค๊ณ  ํ–ˆ์ง€๋งŒ ๊ตณ์ด recoil๋กœ ์™”๋‹ค๊ฐ”๋‹ค ํ•  ํ•„์š”๊ฐ€ ์ „ํ˜€ ์—†์–ด์„œ

ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ •๋ฆฌํ–ˆ๋‹ค.

 

let [todoReadOnly, setTodoReadOnly] = useState(Array(todo.length).fill(true));

 

 

๊ทธ๋ฆฌ๊ณ  ์ด state ๋˜ํ•œ todo๊ฐ€ map์œผ๋กœ ๋ฟŒ๋ ค์ง€๋Š” ๋™์•ˆ index๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— readOnly ์†์„ฑ์— ๋ฐฐ์—ด๋กœ ๋ฟŒ๋ ค์ฃผ์—ˆ๋‹ค.

 

todo.map((todo,index)=>{
    return (
        <Box className="goals-todo-input-list-Box" key={index} onClick={clickTodoModalHandler} data-key={index}>

        {goal.goal_id === parseInt(todo.goal_id) ? (<>
        <div className="goals-todo-input-list-check-wrap">
            <CheckBoxOutlineBlankIcon className="goals-todo-list-input-check-icon"/>
            <input
             key={`todo${index}`} readOnly={todoReadOnly[index]} type="text" maxLength={"35"} name={todo.title} data-index={index} id="todo-input" value={todo.title} onChange={todoEditEventHandler} onKeyDown={enterKeyEventHandler} className="goals-todo-list-input" />

        </div>
        <Button className="goals-todo-list-input-btn" ><MoreHorizIcon className="goals-todo-list-input-btn-icon" /></Button>
        </>
        ) : null} 
        </Box>
    )
})

 

 

์ด๋ ‡๊ฒŒ readonly ์†์„ฑ์„ ๊ฐœ๋ณ„๋กœ ์ค„ ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋ฉด value๊ฐ’์„ e.target.value๋กœ ๋ฐ›์•„์™€์„œ ์ˆ˜์ •๋˜๊ฒŒ ํ•˜๋ฉด ๋˜๊ฒ ๊ตฌ๋‚˜ ํ•˜๊ณ  ์‰ฝ๊ฒŒ ์ƒ๊ฐํ–ˆ๋Š”๋ฐ, ์ƒ๊ฐ๋ณด๋‹ค ์˜ค๋ฅ˜๊ฐ€ ๋งŽ์ด ๋ฐœ์ƒํ–ˆ๋‹ค.

 

e.target.value๋ฅผ recoil๋กœ ๋ฐ›์•„์˜จ todo ๊ฐ์ฒด์˜ title์— state๋ณ€๊ฒฝ ํ•จ์ˆ˜๋กœ ๋„ฃ์œผ๋ ค๊ณ  ํ–ˆ๋”๋‹ˆ 

cannot set properties of undefined (setting 'title') ์˜ค๋ฅ˜๊ฐ€ ์—„์ฒญ ๋–ด๋‹ค.

 

๊ฒฐ๊ตญ ์ฐพ์•„๋ณด๋ฉด ํ•ด๋‹น title์€ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๋Š” '์ฝ๊ธฐ ์ „์šฉ' ์ด๋ผ๋Š” ๊ฑฐ์˜€๋Š”๋ฐ ์Šคํƒ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ์—์„œ๋„ ... ๋”ฅ ์นดํ”ผ๋ฅผ ์ด์šฉํ•˜๋ผ๊ณ  ํ–ˆ์œผ๋‚˜ ์ด๋ฏธ ๋”ฅ ์นดํ”ผ๋ฅผ ์ด์šฉํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.

์ด๊ฒŒ ์•ˆ๋˜๋ฉด JSON์„ ํ…์ŠคํŠธ๋กœ ๋ณ€ํ™˜ํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ํŒŒ์‹ฑํ•˜๋ผ๊ณ  ํ•ด์„œ ํ•ด๋ดค๋Š”๋ฐ๋„ ์•ˆ๋˜๋”๋ผ.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ useRecoilState๋กœ ๋ฐ›์•„์˜จ todo ๊ฐ์ฒด๋ฅผ originTodo๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ฐ›์•„์„œ ๋ฏธ๋ฆฌ ๋”ฅ ์นดํ”ผํ•˜๊ณ , ๊ทธ๊ฑธ ํ•จ์ˆ˜์—์„œ ๋ฐ›์•„ JSON ํŒŒ์‹ฑ์„ ํ•ด์„œ recoilState์™€ ์™„์ „ ๊ด€๋ จ์—†๋Š” ๊ฐ์ฒด๋กœ ๋งŒ๋“ค์–ด๋ฒ„๋ฆฐ ๋‹ค์Œ์— setOriginTodo๋กœ ๋ฎ์–ด์”Œ์šฐ๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋‹ˆ ์ •์ƒ์ ์œผ๋กœ recoil์— ์—…๋ฐ์ดํŠธ ๋˜์—ˆ๋‹ค.

 

 

์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

let [originTodo, setOriginTodo] = useRecoilState(todoData); //recoil์— ์žˆ๋Š” todo ์›๋ณธ ๊ฐ์ฒด
let todo = [...originTodo]; //originTodo Deep Copy

//ํˆฌ๋‘ ํด๋ฆญ-์ˆ˜์ • ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ - ํˆฌ๋‘ ํด๋ฆญํ–ˆ์„ ๋•Œ
const clickTodoEditHandler = (e) => {
    const index = e.currentTarget.dataset.index;
    const newArr = Array(todo.length).fill(true);
    newArr[index] = false;
    setTodoReadOnly(newArr)
    handleTodoModalClose();
}

//ํˆฌ๋‘ ์ˆ˜์ • ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
const todoEditEventHandler = (e) => {
    let index = parseInt(e.target.dataset.index);
    let value = e.target.value;
    const originTodo = JSON.parse(JSON.stringify(todo)); // todo State ์นดํ”ผ
    originTodo[index].title = value;
    setOriginTodo(originTodo) ; //setOriginTodo๋ฅผ ์ด์šฉํ•ด state ๋ณ€๊ฒฝ
}

 

CSS ๋ฅผ ์•ฝ๊ฐ„ ์ˆ˜์ •ํ•ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋งŒ๋“ค์–ด ์ฃผ๋‹ˆ ์•„๋ž˜์™€ ๊ฐ™์ด ๋™์ž‘ํ–ˆ๋‹ค.

maxLength๋„ 35์ž๋กœ ์ค„์˜€๊ณ  ๋ชจ๋‹ฌ์—์„œ๋„ 2์ค„ ์ด์ƒ ๋…ธ์ถœ๋˜์ง€ ์•Š๋„๋ก text-overflow: ellipsis;๋ฅผ ์ฃผ์—ˆ๋‹ค. 

 

 

 

 

๋ฐ”๊นฅ ์ชฝ์„ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ ์—”ํ„ฐ๋ฅผ ์ณค์„ ๊ฒฝ์šฐ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ readOnly๊ฐ€ ๋ฐ”๋€Œ๋ฉด์„œ ์ž๋™์œผ๋กœ submit์ด ๋˜๋Š” ๊ฒƒ ๊ฐ™์ด ๋ณด์ด๊ธฐ ์œ„ํ•ด์„œ ๋‘ ๊ฐ€์ง€์˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค.

 

๊ฐ๊ฐ input์— onKeyDown๊ณผ onBlur๋กœ ์ ์šฉํ–ˆ๋‹ค.

 

 

<input key={`todo${index}`} id="todo-input" className="goals-todo-list-input" type="text" maxLength={"80"} 
name={todo.title} data-index={index} readOnly={todoReadOnly[index]} value={todo.title} 
onChange={todoEditEventHandler} onKeyDown={enterKeyEventHandler} 
onBlur={inputLostFocusEventHandler}  />


//์™ธ๋ถ€ ํด๋ฆญ readonly ๋ณ€๊ฒฝ
const inputLostFocusEventHandler = (e) => {
    let newArr = Array(todo.length).fill(true);
    setTodoReadOnly(newArr)
}

//ํˆฌ๋‘ ์ˆ˜์ • ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
const clickTodoEditHandler = (e) => {
    console.log("ํ˜„์žฌ ์ธ๋ฑ์Šค ", e.currentTarget.dataset.index)
    const index = e.currentTarget.dataset.index;
    const newArr = Array(todo.length).fill(true);
    newArr[index] = false;
    console.log("newArr[index]", index, newArr[index], newArr)
    setTodoReadOnly(newArr)
    handleTodoModalClose();
}

 

 

 

์‚ญ์ œ ๊ธฐ๋Šฅ

 

 

์ˆ˜์ • ๊ธฐ๋Šฅ์ด ํ•˜๋„ ์•ˆ ํ’€๋ ค์„œ ์‚ญ์ œ๋ฅผ ๋จผ์ € ๋งŒ๋“ค์—ˆ์—ˆ๋‹ค. ๊ตฌ์กฐ๋Š” ๋ชฉํ‘œ ๋•Œ์™€ ๋˜‘๊ฐ™์ง€๋งŒ ์ด๋ฒˆ์—” filter๋กœ ๊ฑธ๋Ÿฌ๋‚ผ ์ˆ˜๊ฐ€ ์—†์—ˆ๋‹ค.

 

์™œ๋ƒ๋ฉด ํ˜„์žฌ todo ๊ฐ์ฒด์˜ index ๊ฐ’์„ ์ด์šฉํ•ด์„œ ๋ชจ๋“  ์ •๋ณด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์—

์‚ญ์ œ๋ฅผ ์œ„ํ•ด์„œ goal_id์™€ todo_id๋ฅผ ๋น„๊ตํ•ด์„œ ๋งž๋Š” ๊ฐ’์„ ์ฐพ์•„ filter๋กœ ๊ฑธ๋Ÿฌ๋‚ด๋Š” ๋ณต์žกํ•œ ๋ฐฉ์‹์„ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์•˜๋‹ค.

 

todo๊ฐ€ ์–ด์จŒ๋“  ์ˆœ์„œ๋ฅผ ๊ฐ€์ง„ ๋ฐฐ์—ด๋กœ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๊ณ  ์ˆœํšŒ ๊ฐ€๋Šฅํ•œ ์ •๋ณด.. ์ด๊ธฐ ๋•Œ๋ฌธ์— index๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์‰ฝ๊ณ  ๋นจ๋ž๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹คใ…  

 

 

๊ทธ๋ž˜์„œ ๊ตฌํ˜„ํ•œ ๊ฒƒ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ๋ชจ๋‹ฌ์˜ delete ๋ฒ„ํŠผ์— onClick์œผ๋กœ ์—ฐ๊ฒฐํ•ด ์ฃผ์—ˆ๊ณ  ํด๋ฆญํ•˜๋ฉด ์ฆ‰์‹œ ์‚ญ์ œ๋˜๋„๋ก ํ•˜์˜€๋‹ค.

 

//ํˆฌ๋‘ ์‚ญ์ œ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
const clickTodoDeleteHandler = (e) => {
    let index = parseInt(e.currentTarget.dataset.index);
    const originTodo = [...todo]; // todo State ์›๋ณธ ์นดํ”ผ
    originTodo.splice(index, 1) //์›๋ณธ todo ๋ฐฐ์—ด์—์„œ ํ•ด๋‹น index ์ฐพ์•„์„œ 1๊ฐœ ์‚ญ์ œ
    setOriginTodo(originTodo) ;//setOriginTodo๋ฅผ ์ด์šฉํ•ด state ๋ณ€๊ฒฝ
    handleTodoModalClose();
}

 

์ด๊ฑด spliceํ•œ ๊ฑฐ๋ผ ์ˆ˜์ •์—์„œ ๊ฒช์€ ๊ฒƒ ์ฒ˜๋Ÿผ '์ฝ๊ธฐ ์ „์šฉ' ์˜ค๋ฅ˜๊ฐ€ ๋œจ์ง€๋Š” ์•Š์•˜๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ˆ˜์ •์„ ๋งŒ๋“ค๊ณ  ๋‚˜์„œ ๋”ฅ ์นดํ”ผํ•œ todo๋ฅผ ๋‹ค์‹œ ๋”ฅ ์นดํ”ผํ•ด์„œ ์‚ฌ์šฉํ–ˆ๋‹ค.

์›๋ณธ ๋ถˆ๋ณ€์˜ ๋ฒ•์น™์„ ์žŠ์ง€ ๋ง๊ณ  ๋”ฅ ์นดํ”ผํ•ด์„œ ์‚ฌ์šฉํ•˜์ž. ์ž๊พธ ๋‚  ๊ฒƒ์˜ ์ •๋ณด๋ฅผ ๋œฏ์–ด์„œ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•˜๋‹ˆ๊นŒ ์˜ค๋ฅ˜๊ฐ€ ๋œฌ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ์ˆ˜์ •์ด๊ฑด ์‚ญ์ œ๊ฑด ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ๋ชจ๋‹ฌ์ด ์‚ฌ๋ผ์ ธ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— handleTodoModalClose() ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œ์ผœ ๋ชจ๋‹ฌ์ด ์ข…๋ฃŒ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.

 

์ด์ œ ํ•  ์ผ์€ 3๊ฐœ์˜ ๋‚ ์งœ, ์ˆœ์„œ ๋ณ€๊ฒฝ ๋ฒ„ํŠผ๊ณผ ์ฒดํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์™„๋ฃŒ ์—ฌ๋ถ€ state๊ฐ€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค..!

 

 

 

728x90