Frontend

[React] 프로퍼티 전달, 사용법

Jay_J 2024. 5. 30. 05:49

로그아웃 기능을 구현하던중 문제를 발견했다. 문제가 뭐냐면 나는 Dashboard안에 컴포넌트를 정의했다. 하지만 이 컴포넌트는 Dashboard 밖에서 쓰이는데, Dashboard안에 정의된 handleLogout이라는 컴포넌트의 스코프는 Dashboard컴포넌트 이므로 이 밖에서 쓰려고 하면 undefined에러를 발생 시킬것이다. 그렇다면 이때, 어떻게 해야 할까? 

 

먼저, 아래 코드부터 살펴보자.

 

import React, { useState } from 'react';
import { toast, ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { Button } from 'react-bootstrap';
import { useNavigate } from 'react-router-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import '@fortawesome/fontawesome-free/css/all.min.css'; 

const Sidebar = ({ isOpen, toggleSidebar }) => (
    <div style={{
        width: isOpen ? '250px' : '80px',
        transition: 'width 0.3s',
        backgroundColor: '#800000',
        height: '100vh',
        position: 'fixed',
        color: 'white',
        padding: '1rem',
        overflow: 'hidden',
        zIndex: 1000
    }}>
        <div onClick={toggleSidebar} style={{ cursor: 'pointer', marginBottom: '2rem', display: 'block', visibility: 'visible', position: 'relative' }}>
            <i className="fas fa-bars" style={{ fontSize: '1.5rem', color: 'white' }}></i>
        </div>
        {isOpen && (
            <>
                <div style={{ textAlign: 'center' }}>
                    <img src="profile_picture_url" alt="Profile" style={{ borderRadius: '50%', width: '100px', height: '100px' }} />
                    <h3>Jihoo Jeong</h3>
                    <p>Group 6</p>
                </div>
                <div style={{ marginTop: '2rem', textAlign: 'center' }}>
                    <Button variant="light" style={{ width: '100%', marginBottom: '1rem', backgroundColor: '#6a5acd', color: 'white' }}>Dashboard</Button>
                    <Button variant="light" style={{ width: '100%', marginBottom: '1rem', backgroundColor: '#6a5acd', color: 'white' }}>Teams</Button>
                    <Button variant="light" style={{ width: '100%', marginBottom: '1rem', backgroundColor: '#6a5acd', color: 'white' }}>Settings</Button>
                </div>
                <div style={{ marginTop: 'auto', textAlign: 'center' }}>
                    <Button variant="secondary" style={{ backgroundColor: '#6a5acd', width: '100%' }}>Create Teams</Button>
                    <Button onClick = {handleLogout} variant="danger" style={{ marginTop: '1rem', width: '100%' }}>Sign Out</Button>
                </div>
            </>
        )}
    </div>
);

const Card = ({ children, header }) => (
    <div className="card" style={{ borderRadius: '1rem', backgroundColor: '#ffe4e1', border: '1px solid #ccc', margin: '1rem 0' }}>
        <div className="card-header" style={{ backgroundColor: '#f08080', color: 'white', borderRadius: '1rem 1rem 0 0', padding: '1rem' }}>
            <h3 className="mb-0">{header}</h3>
        </div>
        <div className="card-body p-5 text-center">
            {children}
        </div>
    </div>
);

const Container = ({ children }) => (
    <div style={{ display: 'flex' }}>
        {children}
    </div>
);

const MainContent = ({ children, isSidebarOpen }) => (
    <div style={{
        marginLeft: isSidebarOpen ? '250px' : '80px',
        padding: '2rem',
        width: '100%',
        transition: 'margin-left 0.3s'
    }}>
        {children}
    </div>
);


const Dashboard = () => {
    const [isSidebarOpen, setSidebarOpen] = useState(false);
    const navigate = useNavigate();

    const toggleSidebar = () => {
        console.log("Sidebar toggled");
        setSidebarOpen(!isSidebarOpen);
    };

    const handleGiveFeedback = (event) => {
        event.preventDefault();
          navigate('/Givefeedback');
    };

    const handleLogout = () => {
        const casLogoutUrl = 'https://login.vt.edu/profile/cas/logout';
        window.location.href = casLogoutUrl;
    }

    return (
        <div>
            <ToastContainer />
            <Container>
                <Sidebar isOpen={isSidebarOpen} toggleSidebar={toggleSidebar} />
                <MainContent isSidebarOpen={isSidebarOpen}>
                    <h1>Dashboard</h1>
                    <Card header="Student Group 1">
                        <p>Jaison Dasika, Kristian Braun, Jihoo Jeong, Somin Yun</p>
                        <Button onClick={handleGiveFeedback} variant="primary">Give Feedback</Button>
                    </Card>
                    <Card header="Student Group 2" />
                    <Card header="Student Group 3" />
                    <Card header="Student Group 4" />
                </MainContent>
            </Container>
        </div>
    );
};

export default Dashboard;

- 보면 Dashboard안에 handleLogout이 정의되어있다. 이렇게 되면 Dashboard 컴포넌트 밖에서는 단순 호출을 할 수 없다. 이럴때, 내가 사용하고 싶은곳에 프로퍼티로 넘겨줄 수 있다. 

 

- 내 애플리케이션은 'Sign out' 버튼이 Sidebar 컴포넌트 안에 정의되어 있으므로(여기서 사용할것이므로), Sidebar 컴포넌트안에 프로퍼티로 넘겨준다. 넘겨주는 방식은 아래와 같다.

 

const Sidebar = ({ isOpen, toggleSidebar, handleLogout }) => (
    <div style={{
        width: isOpen ? '250px' : '80px',
        transition: 'width 0.3s',
        backgroundColor: '#800000',
        height: '100vh',
        position: 'fixed',
        color: 'white',
        padding: '1rem',
        overflow: 'hidden',
        zIndex: 1000
    }}>

 

{} 여기 안에 프로퍼티로 넘겨줄 함수, 인자들을 넘겨주면 이제 Sidebar안에서도 Dashboard안에 정의되어있는 컴포넌트들을 호출 할 수 있다.

 

그런데, 이렇게 코드를 수정하다가 의문이 들었다. "아니 그렇다면, 그냥 Dashboard가 아니라 Dashboard 밖에 global 함수로 선언하면 더 편할텐데?"

컴포넌트 내부에서 함수 정의

컴포넌트 내부에서 함수를 정의하면 해당 함수는 컴포넌트의 상태(state)와 props에 접근할 수 있다. 이는 함수가 컴포넌트의 동작에 직접적으로 연관된 경우 유용하다.

장점:
- 컴포넌트의 상태와 props에 접근 가능.
- 함수가 해당 컴포넌트의 라이프사이클과 연관될 수 있음.

단점:
- 함수가 컴포넌트 내부에 정의되어 있을 때마다 새로 생성됨. 이로 인해 메모리 사용량이 증가할 수 있음.
- 컴포넌트가 커질수록 복잡성이 증가할 수 있음.

※컴포넌트 외부에서 함수 정의
컴포넌트 외부에서 함수를 정의하면 해당 함수는 독립적으로 동작하며, 특정 컴포넌트에 종속되지 않는다. 이는 함수가 다른 컴포넌트에서도 재사용되거나, 특정 컴포넌트의 상태나 props에 의존하지 않는 경우 유용하다.

장점:
- 재사용성이 높아짐. 여러 컴포넌트에서 동일한 함수를 사용할 수 있음.
- 컴포넌트의 복잡성을 줄일 수 있음.

단점:
- 함수가 컴포넌트의 상태나 props에 접근할 수 없음. 이로 인해 필요한 데이터는 모두 함수 호출 시 전달해야 함.
- 컴포넌트와 함수 간의 결합도가 낮아짐. 이로 인해 특정 상황에서는 불편할 수 있음.

 요약
- 내부 정의: 상태와 props에 직접 접근할 수 있으며, 컴포넌트의 라이프사이클과 밀접하게 연관된 경우 유리하다.
- 외부 정의: 재사용성과 코드의 간결성을 높일 수 있으며, 컴포넌트에 종속되지 않는 함수에 적합하다.