Programming/React

[ React ] ๋ฐ˜์‘ํ˜•์›น์—์„œ ๊ณ„์† ๋ณ€ํ•˜๋Š” ๋ฒ„ํŠผ ์œ„์น˜ ์ฐพ์•„๋‚ด๊ธฐ, ๋ฒ„ํŠผ ๋ฐ‘์— edit ํ•  ์ˆ˜ ์žˆ๋Š” ๊ทธ๋ฆฌ๋“œ ๋ถ™์ด๊ธฐ

seulye 2023. 5. 26. 15:33

 

- ๋ชฉํ‘œ

๋ฐ˜์‘ํ˜•์›น์—์„œ ํŠน์ • ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋ฐ”๋กœ ๋ฐ‘์— edit box๋ฅผ ๋„์›Œ์ง€๋Š” ๊ฒƒ

ํšŒ์‚ฌ ํ”„๋กœ๊ทธ๋žจ ํ™”๋ฉด์„ ๋ณด์—ฌ์ค„ ์ˆ˜๋Š” ์—†์œผ๋‹ˆ ํ”ผ๊ทธ๋งˆ๋กœ ๋Œ€์ถฉ ๊ทธ๋ ค๋ณด์•˜๋‹ค. 

 

โ€ป Button๊ณผ Grid ๋ชจ๋‘ mui ์‚ฌ์šฉ

 

1. Button์— ref ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๊ธฐ 

const buttonRef = useRef<HTMLButtonElement>(null);
const [showTextBox, setshowTextBox] = useState(false); // true์ผ๋•Œ edit box ๋ณด์—ฌ์ง

<Button onClick={textBoxPopUp} ref={multipleButtonRef}>
        Button
</Button>

{showTextBox ? (
                    <Grid
                        alignItems="top"
                        justifyContent="flex-end"
                        style={{
                            position: 'absolute',
                            top: buttonRef?.current?.getBoundingClientRect?.()?.bottom + 5 ?? undefined,
                            left: buttonRef?.current?.getBoundingClientRect?.()?.left ?? undefined
                        }}
                    >
                        <Grid item>
                            <textarea
                                className={theme.palette.mode === 'dark' ? 'ag-theme-balham-dark' : 'ag-theme-balham'}
                                style={{ minHeight: 270, minWidth: 200 }}
                                onKeyUp={handleKeyPress}
                                defaultValue={text.current}
                            />
                        </Grid>
                    </Grid>
                ) : null}

multipleButtonRef?.current?.getBoundingClientRect?.()?.bottom

์ด ๋ถ€๋ถ„์ด ํ•ต์‹ฌ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. 

multipleButtonRef?.current?.getBoundingClientRect()๋กœ ๋ฒ„ํŠผ์˜ ํ˜„์žฌ ์œ„์น˜๋ฅผ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค. 

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Object is possibly 'undefined'. ์˜ค๋ฅ˜๊ฐ€ ๋œฌ๋‹ค

buttonRef์˜ ์ดˆ๊ธฐ๊ฐ’์ด null์ด๋‹ค ๋ณด๋‹ˆ๊นŒ ์˜ต์…”๋„ ์ฒด์ด๋‹ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ์˜ค๋ฅ˜๊ฐ€ ๋œจ๋Š” ๊ฒƒ ๊ฐ™๋‹ค. 

์ดˆ๊ธฐ๊ฐ’์„ null๋ง๊ณ  ๋‹ค๋ฅธ ๊ฑธ๋กœ ์„ค์ •ํ•ด์•ผํ•˜๋‚˜.. ํ•˜๋‹ค๊ฐ€ ๋ญ˜๋กœ ์„ค์ •ํ•ด์ค„์ง€๋ฅผ ๋ชจ๋ฅด๊ฒ ์–ด์„œ.. ์ผ๋‹จ ๋ƒ…๋’€๋‹ค ๐Ÿฅน

์ด๊ฒŒ ์ž˜ ๋จนํ˜”๋‹ค๋ฉด ์ •๋ง ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ์„ํ…๋ฐ... 

 

+ top: buttonRef?.current?.getBoundingClientRect?.()?.bottom + 5 ?? undefined,

์ด ๋ถ€๋ถ„์„

top: buttonRef?.current?.getBoundingClientRect?.()?.bottom ?? 0 + 5 ?? undefined,

์œผ๋กœ ๋ฐ”๊ฟจ๋”๋‹ˆ ์ž˜ ๋จน๋Š”๋‹ค!!!

 

+ ๊ทผ๋ฐ ๋ฌ˜ํ•˜๊ฒŒ ์œ„์น˜๊ฐ€ ์ด์ƒํ•จ..

 

 

2. Button ํด๋ฆญ ์ด๋ฒคํŠธ, ์ฐฝ ํฌ๊ธฐ ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ ์ด์šฉํ•˜๊ธฐ

 

- ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ์ด๋ฒคํŠธ 

const [textPos, setTextPos] = useState<{ mouseX: number; mouseY: number } | null>(null);

const textBoxPopUp = async (event: any) => {
        const pos = event.target.getBoundingClientRect();

        setTextPos({
            mouseX: pos.left,
            mouseY: pos.bottom + 5
        });
    };
    
    
<Button onClick={textBoxPopUp} ref={multipleButtonRef}>
        Button
</Button>

{showTextBox ? (
                    <Grid
                        alignItems="top"
                        justifyContent="flex-end"
                        style={{
                            position: 'absolute',
                            top: textPos ? textPos.mouseY : undefined,
                            left: textPos ? textPos.mouseX : undefined
                        }}
                    >
                        <Grid item>
                            <textarea
                                className={theme.palette.mode === 'dark' ? 'ag-theme-balham-dark' : 'ag-theme-balham'}
                                style={{ minHeight: 270, minWidth: 200 }}
                                onKeyUp={handleKeyPress}
                                defaultValue={text.current}
                            />
                        </Grid>
                    </Grid>
                ) : null}

 

์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€, textPos๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด์„œ text box์˜ ์œ„์น˜๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. 

 

 

- ์ฐฝ ํฌ๊ธฐ ๋ณ€๊ฒฝ 

useEffect(() => {
        const handleWindowResize = () => {
            setWindowSize({
                width: window.innerWidth,
                height: window.innerHeight
            });
        };

        window.addEventListener('resize', handleWindowResize);

        return () => {
            window.removeEventListener('resize', handleWindowResize);
        };
    }, []);

    useEffect(() => {
        // ์ฐฝ ํฌ๊ธฐ ๋ณ€๊ฒฝ
        const pos = buttonRef.current?.getBoundingClientRect?.();

        if (showTextBox && pos) {
            setTextPos({
                mouseX: pos.left,
                mouseY: pos.bottom + 5
            });
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [windowSize]);

์ฐฝํฌ๊ธฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค textPos๋ฅผ ๋ณ€๊ฒฝํ•ด์ค€๋‹ค. 

๋งค์šฐ ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ๋ณ€๊ฒฝ๋˜์ง„ ์•Š์ง€๋งŒ.. ์ผ๋‹จ ๋ชฉํ‘œ ๋‹ฌ์„ฑ !!!!