React 부모, 자식 관계

limchard·2023년 12월 12일
0

React

목록 보기
5/7

- 한 부모에 자식이 여럿 있을 수 있다.
- 부모만이 App.js와 소통할 수 있다.
- 즉, 자식은 App.js와 소통할 수 없다.
- 부모의 정보를 받으면 자식입장에서는 단순 읽기전용으로 받는다.
- 자식이 부모에 영향을 주기 위해선 event가 필요하다.


SixApp.js

  • 자식에게 넘겨줄 변수를 입력할 수 있다.
import React, {useState} from 'react';
import SixSubApp from "./SixSubApp";
import SixSubApp2 from "./SixSubApp2";
import SixSubApp3 from "./SixSubApp3";

function SixApp(props) {

    const [number,setNumber]=useState(10);
    // 증가 이벤트
    const NumberIncre=()=>{
        setNumber(number+1);
    }
    // 감소 이벤트
    const NumberDecre=()=>{
        setNumber(number-1);
    }

    return (
        <div>
            <h3 className={'alert alert-dark'}>SixApp입니다._부모자식간 컴포넌트통신</h3>
            <SixSubApp name={'뽀로로'} age={'7'}/>
            <SixSubApp name={'포비'} age={'54'}/>
            <SixSubApp name={'루피'} age={'31'}/>
        {/*    자식은 연속적으로 여러개 호출도 가능하다. */}
        {/*  props 라는 변수로 name, age 전달 가능하다.  */}
            <br/><br/>
            <SixSubApp2 flower={"수국"} price={'25000'} linecolor={'purple'}/>
            <SixSubApp2 flower={"벚꽃"} price={'35000'} linecolor={'pink'}/>
            <SixSubApp2 flower={"장미"} price={'20000'} linecolor={'red'}/>
            <SixSubApp2 flower={"매화"} price={'50000'} linecolor={'yellow'}/>
            <SixSubApp2 flower={"안개꽃"} price={'10000'} linecolor={'tomatos'}/>
            <br/><br/>
            <div className={'number'}>{number}</div>
            <SixSubApp3 incre={NumberIncre} decre={NumberDecre}/>
        </div>
    );
}

export default SixApp;

SixSubApp.js

  • 부모에서 준 변수들을 props.변수 로 받아올 수 있다.
import React from 'react';


function SixSubApp(props) {
    console.dir(props);
    return (
        <div>
            <h3 className={'alert alert-primary'}>SixApp의 첫째 자식입니다.</h3>
            <div className={'line'}>{props.name}님의 나이는 {props.age}세 입니다.</div>
        </div>
    );
}

export default SixSubApp;

SixSubApp2.js

  • 중괄호{}를 이용하여 변수를 직접적으로 받을 수 있다.
import React from 'react';

function SixSubApp2({flower,price,linecolor}) { // props 를 지우고, 직접 받을 수 있음.
    return (
        <div>
            <h3 className={'alert alert-danger'}>SixApp의 둘째입니다.</h3>
            <h3 className={'line'} style={{borderColor:linecolor}}>{flower} 1묶음 가격은 {price} 입니다.</h3>
        </div>
    );
}

export default SixSubApp2;

SixSubApp3.js

  • 부모의 이벤트를 이용할 수 있다.
import React from 'react';

function SixSubApp3(props) {
    return (
        <div>
            <h3 className={'alert alert-danger'}>SixApp의 셋째입니다.</h3>
            <button className={'btn btn-danger'} onClick={props.incre}>증가</button>
            <button className={'btn btn-warning'} onClick={()=>{
            props.decre();
            }}>감소</button>

        </div>
    );
}

export default SixSubApp3;


추가 예제

OneApp.js

  • 객체변수화를 통해 기본 정보를 담아둔다.
  • 변수를 넘겨줄 때 각각 기입해도 되지만 펼침 연산자를 통해 간편하게 입력 가능하다.
  • 부모에서 이벤트를 생성해서 자식에게 넘겨준다. 자식은 단순 호출만으로 사용 가능하다.
import React, {useState} from 'react';
import Stack from "@mui/material/Stack";
import Alert from "@mui/material/Alert";
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
import RowItemApp from "./RowItemApp";
import WriteForm from "./WriteForm";

function OneApp(props) {

    // 객체변수화
    const [board,setBoard]=useState([
        {
            name:'유재석',
            photo:'1',
            blood:'A',
            today:new Date()
        },
        {
            name:'강호동',
            photo:'2',
            blood:'B',
            today:new Date()
        },
        {
            name:'하하',
            photo:'3',
            blood:'O',
            today:new Date()
        },
        {
            name:'지석진',
            photo:'4',
            blood:'O',
            today:new Date()
        },
        {
            name:'박명수',
            photo:'5',
            blood:'AB',
            today:new Date()
        },
    ]);

    // 데이터 추가하는 함수 이벤트
    // board를 바꾸면 렌더링이 되면서 추가된다.
    const datasave=(data)=>{
        setBoard(board.concat({
            // name: data.name,
            // photo: data.photo,
            // blood: data.blood,
            ...data,
            today: new Date()
        }))
    }

    // 삭제 이벤트
    const dataDelete=(idx)=>{
        setBoard(board.filter((item,i)=>(i!==idx))); // i가 idx 값과 다른 값만 취합한다. 그래서 setBoard에 다시 렌더링한다.
    }

    return (
        <div style={{marginLeft:'100px'}}>
            <Stack sx={{ width: '100%' }} spacing={2}>
                <Alert severity="info">OneApp<AutoAwesomeIcon/></Alert>
                <WriteForm onSave={datasave}/>

                <table className={'table table-bordered'} style={{width:'600px'}}>
                    <caption align={'top'}><b>Board 배열 출력 연습</b></caption>
                    <thead>
                        <tr className={'table-success'}>
                            <th width={'100'}>이름</th>
                            <th width={'120'}>사진</th>
                            <th width={'80'}>혈액형</th>
                            <th width={'160'}>날짜</th>
                            <th width={'70'}>삭제</th>
                        </tr>
                    </thead>
                    <tbody>
                    {
                        // 데이터 개수만큼 호출된다... 출력은 아직 안됨... 출력은 RowItemApp.js 에서 해야한다.
                        board.map((row,index)=>(<RowItemApp row={row} idx={index} onDelete={dataDelete} />)) // index 값을 무조건 넘겨줘야 기준점을 잡고 삭제 가능하다.
                    }
                    </tbody>
                </table>
            </Stack>
        </div>
    );
}

export default OneApp;

RowItemApp.js

import React from 'react';

// function RowItemApp({row,idx,onDelete}) {
function RowItemApp(props) {

    let {row,idx,onDelete}=props; //

    // 삭제이벤트
    const btnDelete=()=>{
        onDelete(idx); // 부모가 props로 보낸 이벤트 호출하는 것.
    }

    return (
        <tr>
            <td>{row.name}</td>
            <td><img src={`../image/s${row.photo}.JPG`} style={{width:'100px',border:'1px solid gray'}}/></td>
            <td>{row.blood}</td>
            <td>{row.today.toLocaleString('ko-kr')}</td>
            {/*<td>{row.today.toDateString()}</td>*/}
            <td>
                <button type={"button"} className={'btn btn-outline-danger btn-sm'} onClick={btnDelete} >삭제</button>
            </td>

        </tr>
    );
}

export default RowItemApp;

WriteForm.js

import React, {useState} from 'react';

function WriteForm({onSave}) {

    const [name,setName]=useState();
    const [photo,setPhoto]=useState();
    const [blood,setBlood]=useState();

    // 부모에게서 받은 버튼 이벤트 생성
    const addDataEvent=()=>{
        // 부모 컴포넌트에서 만든 onSave를 호출만하면 된다.
        onSave({name,photo,blood});
    }

    return (
        <div>
            <b>이름:</b>
            <input type={"text"} style={{width:'100px'}} onChange={(e)=>{
                setName(e.target.value);
            }}/>
            <b>이미지:</b>
            <select onChange={(e)=>{
                setPhoto(e.target.value)
            }}>
                {
                    // 1~10 까지 map 으로 돌리기 s1~s10
                    [...new Array(10)].map((a,idx)=>(<option>{`${idx+1}`}</option>))
                }
            </select>

            <b>혈액형:</b>
            <select onChange={(e)=>{
                setBlood(e.target.value)
            }}>
                <option>A</option>
                <option>B</option>
                <option>O</option>
                <option>AB</option>
            </select>

            <button type={"button"} className={'btn btn-info'} style={{marginLeft:'10px'}} onClick={addDataEvent}>추가</button>
        </div>
    );
}

export default WriteForm;


TwoApp.js

import React, {useState} from 'react';
import Alert from '@mui/material/Alert';
import Brightness2Icon from '@mui/icons-material/Brightness2';
import TwoSubApp from "./TwoSubApp";

function TwoApp(props) {

    const [color,setColor]=useState('pink');
    const [message,setMessage]=useState('오늘은 수요일^^');
    const [photo,setPhoto]=useState('s7');

    // 3개의 이벤트를 만들어 전달
    const changeMessage=(msg)=>{
        setMessage(msg);
    }
    const changeColor=(color)=>{
        setColor(color);
    }
    const changeImage=(img)=>{
        setPhoto(img);
    }

    return (
        <div>
            <Alert severity="success">TweApp<Brightness2Icon/></Alert>
            <br/>
            <h1 style={{color:color}}>{message}</h1>
            <img src={`../image/${photo}.JPG`} style={{width:'100px'}}/>
            <br/>
            <TwoSubApp onMessage={changeMessage} onColor={changeColor} onPhoto={changeImage}/>
        </div>
    );
}

export default TwoApp;

TwoSubApp.js

import React from 'react';

function TwoSubApp(props) {
    return (
        <div style={{marginLeft:'100px'}}>
            <b>메세지</b>
            <input type={"text"} className={'form-control'} style={{width:'400px'}}
                   onChange={(e)=>{
                props.onMessage(e.target.value)
            }}/>
            <br/>
            <b>글자색변경</b>
            <input type={"color"} defaultValue={'#ffc'} className={'form-control'}
                   style={{width:'400px'}} onChange={(e)=>{
                       props.onColor(e.target.value)
            }}/>
            <br/>
            <b>이미지변경</b>
            <select className={'form-control'} style={{width:'400px'}} onChange={(e)=>{
                props.onPhoto(e.target.value)
            }}>
                {
                    [...new Array(10)].map((a,idx)=>(<option>{`s${idx+1}`}</option>))
                }
            </select>
        </div>
    );
}

export default TwoSubApp;

profile
java를 잡아...... 하... 이게 맞나...

1개의 댓글

comment-user-thumbnail
2023년 12월 12일

정말 깔끔한 설명이네요! 전공자이신가요?

답글 달기