Notice
Recent Posts
Recent Comments
Link
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

오늘도 코딩하나

[moneybook]_day5 본문

React/Daily

[moneybook]_day5

오늘도 코딩하나 2024. 8. 30. 23:58

1. (issue) 문자열 선택

초기값 세팅으로 0이 세팅된 후에도 selectText() 함수가 실행되어 문자열 전체 선택이 되야하는데, 안되넹

 

- 수정 후 소스

const setInitial = (e, item) => {
    const today = new Date();
    const date = `${today.getFullYear()}-${String(today.getMonth()+1).padStart(2,'0')}-${today.getDate()}`;
    
    if(item.disabled) {
    	const newData = tempData.map((i) =>
        	item.id === i.id ? { ...i, date, price1:0, price2:0, isDisabled: false } : i
        )
        setTempData(newData);
        
        setTimeout(() => selectText(e), 0);
    } else {
    	selectText(e);
    }
}

 

기존에는 selectText(e)를 그냥 호출했다.

 

[원인] React의 상태 업데이트와 브라우저의 DOM 갱신 타이밍 차이

(1) 상태 업데이트로 인한 비동기 재렌더링

   - 상태 업데이트는 비동기적으로 처리되며, React는 변경된 상태를 기반으로 컴포넌트를 다시 렌더

   - 이 재렌더링 과정이 끝나기 전에 selectText 함수가 호출될 수 있다.

(2) 브라우저의 DOM 갱신 타이밍

   - 항목의 상태 변경에 대한 DOM 반영 전 selectText 호출

 

[해결 방법] SetTimeout

   - setTimeout을 사용하여 selectText 호출을 지연시키면,

     React가 상태 업데이트로 인해 컴포넌트를 다시 렌더링하고 DOM이 완전히 준비된 후에 텍스트 선택이 실행된다.

 

 

2. DB 연동

 

- server.js

const express = require('express');
const db = require('./database/db')
const app = express();
const path = require('path');
const port = 8009;

app.listen(port, function() {
    console.log(`listening on ${port}`);
})

app.use(express.json());
var cors = require('cors');
app.use(cors());

app.use(express.static(path.join(__dirname, '../account/build')))

app.get('/payList', function(req, res) {
    db.query('SELECT id, date, group1, group2, price1, price2, payment, remark FROM PAYLIST', function (err, results, fields) {
        if(err) throw err;
        res.send(results);
    })
})

app.post('/payList/insert', function(req, res) {
    console.log(req);
    const data = req.body;

    data.forEach(item => {
        if(item.isNew) {
            db.query('INSERT INTO PAYLIST (date, group1, group2, price1, price2, payment, remark) VALUES (?, ?, ?, ?, ?, ?, ?)',
            [item.date, item.group1, item.group2, item.price1, item.price2, item.payment, item.remark],
            (err, result) => {
                if(err) throw err;
            });
        } else if(item.isModified) {
            db.query('UPDATE PAYLIST SET date = ?, group1 = ?, group2 = ?, price1 = ?, price2 = ?, payment = ?, remark = ? WHERE id = ?',
            [item.date, item.group1, item.group2, item.price1, item.price2, item.payment, item.remark, item.id],
            (err, result) => {
                if(err) throw err;
            });
        }
    });

    res.send({ message: 'Data saved successfully!'});
});

app.get('*', function(req, res) {
    res.sendFile(path.join(__dirname, '../account/build', 'index.html'));
})

 

 

- paySlice.js

import { configureStore, createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import axios from 'axios';

// 비동기 thunk : MySQL에서 데이터 가져오기
export const fetchData = createAsyncThunk('payList/fetchData', async () => {
    const response = await axios.get('http://localhost:8009/payList');
    return response.data;
});

// 비동기 thunk : MySQL에서 데이터 저장하기
export const saveData = createAsyncThunk('payList/saveData', async (data) => {
    const response = await axios.post('http://localhost:8009/payList/insert', data);
    return response.data;
})

let payList = createSlice({
    name : 'payList',
    initialState : {
        items: [],
        status: 'idle',
        error: null,
    },
    extraReducers: (builder) => {
        builder
            .addCase(fetchData.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(fetchData.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.items = action.payload;
            })
            .addCase(fetchData.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.error.message;
            })
            .addCase(saveData.fulfilled, (state, action) => {
                state.items = action.payload;
            })
    }
})

 

 

- PayList.js

function PayList() {
	// 저장하기
    const handleSave = () => {
        const modifiedData = tempData.filter(item => item.isModified || item.isNew);
        console.log(modifiedData);
        if(modifiedData.length > 0) {
            dispatch(saveData(tempData));   
        }
    }
    
	return (
    	{payListStatus === 'loading' && <div>Loading...</div>}

        {payListStatus === 'succeeded' && (
            tempData.map((item,i) => (
                <tr key={i}>
                    <td><input type="checkbox" checked={checkedItems.includes(item.id)} onChange={() => handleCheck(item.id)} disabled={item.isDisabled} /></td>
                    {columns.map((col, idx) => (
                        <Input
                        key={col}
                        ref={el => inputRefs.current[i * 7 + idx] = el}
                        onBlur={(e) => handleUpdate(item.id, col, e.target.innerText)}
                        onKeyDown={(e) => handleKeyDown(e, (i + 1) * 7 + idx, e)}
                        onFocus={(e) => setInitial(item, i * 7 + idx)}>
                            {col.includes('price') && !isNaN(item[col]) ? Number(item[col]).toLocaleString('ko-KR') : item[col]}
                        </Input>
                    ))}
                </tr>
            ))
        )}

        {payListStatus === 'failed' && (
            <tr>
                <td colspan="8">Error</td>
            </tr>
        )}
    )
}

 

React + Redux + MySQL

DB에서 데이터를 불러오고, 새로운 데이터를 DB에 저장하는 것까지 완료했다!

 

 

** DB 세팅에 대한 내용은 하단 링크에 정리해둠

https://coding-hana.tistory.com/49

 

[React] nodejs + mysql 연동

(1) server 세팅npm init -ynpm install expressnpm install nodemonnpm install cors - server.jsconst express = require('express');const db = require('/database/db');const app = express();const path = require('path')const port = 8009;app.listen(port, functi

coding-hana.tistory.com

 

'React > Daily' 카테고리의 다른 글

[moneybook]_day6  (0) 2024.09.02
[moneybook]_day4  (0) 2024.08.29
[moneybook]_day3  (0) 2024.08.24
[moneybook]_day2  (0) 2024.08.24
[moneybook]_day1  (0) 2024.08.22