리액트

리액트> 자식이 부모의 state 가져다쓰고 싶을 때는 props

연습노트 2024. 7. 12. 16:38

<Modal>안에 글제목 state 가 필요한데

 

저번에 만든 <Modal> 내부에 글제목 state를 집어넣고 싶으면 어떻게하죠? 

예를 들면 이렇게 하면 될듯요 

 

 

function App (){
  let [글제목, 글제목변경] = useState(['남자코트 추천', '강남 우동맛집', '파이썬독학']);
  return (
    <div>
      <Modal></Modal>
    </div>
  )
}

function Modal(){
  return (
    <div className="modal">
      <h4>{ 글제목[0] }</h4>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

▲ 하지만 제대로 실행되지 않습니다.

'글제목'이라는 변수가 define 되지 않았다고 에러가 뜹니다.

왜냐면 글제목이라는 state 변수는 function App()에 있지 function Modal()에 없으니까요.

자바스크립트에선 다른 함수에 있는 변수를 마음대로 가져다쓸 수 없습니다. 

 

 

 

 

 

 

근데 컴포넌트 2개가 부모/자식 관계인 경우엔 가능합니다. 

(다른 컴포넌트 안에 있는 컴포넌트를 자식컴포넌트라고 부릅니다)

 

 

 

 

부모 컴포넌트의 state를 자식 컴포넌트로 전송해줄 수 있습니다. 그럼 자식도 사용가능

전송시엔 props라는 문법을 사용합니다. 

 

 

 

 

 

 

 

props로 부모 -> 자식 state 전송하는 법 

 

2개의 step을 따라주시면 됩니다.

1. 자식컴포넌트 사용하는 곳에 가서 <자식컴포넌트 작명={state이름} /> 

2. 자식컴포넌트 만드는 function으로 가서 props라는 파라미터 등록 후 props.작명 사용

하지만 이론만 설명하면 이해가 되지 않으니 예시를 보아야합니다.

 

 

 

글제목이라는 부모 컴포넌트의 state를 자식 컴포넌트 <Modal>에 전송해봅시다.

function App (){
  let [글제목, 글제목변경] = useState(['남자코트 추천', '강남 우동맛집', '파이썬독학']);
  return (
    <div>
      <Modal 글제목={글제목}></Modal>
    </div>
  )
}

function Modal(props){
  return (
    <div className="modal">
      <h4>{ props.글제목[0] }</h4>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

1. 자식컴포넌트 사용하는 곳에 가서 <자식컴포넌트 작명={state이름} /> 

2. 자식컴포넌트 만드는 곳에 가서 props라는 파라미터 등록 후 props.작명 사용하면 됩니다.

props 전송문법은 중요하니 외워두도록 합시다. 

 

 

 

 

(참고1) props는 <Modal 이런거={이런거}  저런거={저런거}> 이렇게 10개 100개 1000개 무한히 전송이 가능합니다.

(참고2) 꼭 state만 전송할 수 있는건 아닙니다. 

<Modal 글제목={변수명}> 일반 변수, 함수 전송도 가능하고 

<Modal 글제목="강남우동맛집"> 일반 문자전송은 중괄호 없이 이렇게 해도 됩니다.

 

 

 

 

▲ 자식 → 부모 패륜방향 전송은 불가능합니다.

 

 

 

▲ 옆집 컴포넌트로의 불륜전송도 불가능합니다. 

 

 

 

 

 

 

props는 함수 파라미터 문법이랑 똑같습니다

 

함수에 파라미터같은거 왜 넣죠?

자바스크립트 기초강의에서는 

"함수 하나로 다양한 기능을 사용하기 위해서 쓰는게 파라미터 문법" 이랬습니다.

props도 실은 파라미터랑 똑같은 문법입니다. 

그래서 이런 식으로 응용도 가능한데 

 

 

function Modal(props){
  return (
    <div className="modal" style={{ background : 'skyblue' }}>
      <h4>{ props.글제목[0] }</h4>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

갑자기 하늘색 배경의 모달창이 필요하면 저렇게 스타일 넣으면 됩니다. 

근데 이번엔 오렌지색 모달창이 필요하면 어떻게합니까? 

갑자기 노란색 모달창도 필요하면요?

 

가장 쉬운 방법은

function Modal2() {}

function Modal3() {}

....

이렇게 컴포넌트를 또 만들어서 각각 배경색을 다르게 만들어도 되겠지만 

내용이 똑같은데 배경색만 다르면 굳이 같은 함수 여러개 만들 필요가 없습니다. 

 

 

 

function Modal(props){
  return (
    <div className="modal" style={{ background : props.color }}>
      <h4>{ props.글제목[0] }</h4>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

props.color 이런 식으로 구멍을 뚫어놓으면 이제 컴포넌트 사용할 때

<Modal color={'skyblue'} /> 이러면 하늘색 모달창이 생성됩니다. 

<Modal color={'orange'} /> 이러면 오렌지색 모달창이 생성됩니다.

그래서 비슷한 컴포넌트를 또 만들 필요가 없어지는 것입니다. 

1. html css로 미리 디자인해놓고 

 

다 한것 같군요 패스합시다 

 

 

 

 

2. 현재 UI의 상태를 state로 만들어두고

 

let [title, setTitle] = useState(0);

그래서 저는 function App(){} 안에 state 하나 만들었습니다. 

모달창 안의 글제목은 0번글이 보이거나 1번글이 보이거나 2번글이 보이거나 

이런 상태밖에 없어서 그냥 숫자로 표현하고 싶어서 숫자적어놨습니다. 

 

 

 

 

3. state에 따라서 UI가 어떻게 보일지 작성

 

설명하다
 
function App (){
  let [title, setTitle] = useState(0);
  (생략)
}

function Modal(props){
  return (
    <div className="modal">
      <h4>{ 만약에 title == 0이면 0번 글제목 보여주세요~ }</h4>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

만약에 title == 0이면 props.글제목[0] 보여주세요~

만약에 title == 1이면 props.글제목[1] 보여주세요~

이렇게 코드짜면 기능완성입니다. 

당연히 조건문 같은거 사용하면 됩니다.

 

 

 

설명하다
 
function App (){
  let [title, setTitle] = useState(0);
  (생략)
}

function Modal(props){
  return (
    <div className="modal">
      <h4>{ props.글제목[title] }</h4>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

근데 이렇게 해도 될듯요 

그럼 title이 0이면 props.글제목[0] 보이지 않겠습니까 

아무튼 기능완성인데 왜 에러가 나는 것이죠

 

왜겠습니까

 

title이라는 state는 부모가 가진 state라서 

자식이 사용하고 싶으면 props로 전송해야합니다. 전송하십시오 

 

 

설명하다
 
function App (){
  let [title, setTitle] = useState(0);
  (생략)
  {
    modal == true ? <Modal title={title} 글제목={글제목} /> : null
  }
}

function Modal(props){
  return (
    <div className="modal">
      <h4>{ props.글제목[props.title] }</h4>
      <p>날짜</p>
      <p>상세내용</p>
    </div>
  )
}

props로 전송했습니다. UI 만들기 끝 

이제 스위치를 다 만들어놨기 때문에

title이라는 스위치를 0, 1, 2로 바꿔주면 그 때마다 알맞은 글이 모달창에 표시됩니다.

 

[collapse]

 

 

 

 

 

 

글에 onClick 집어넣으면 끝임 

 

이제 글을 클릭할 때 스위치만 샤샥 바꿔주면 원하는 기능구현 끝입니다.

0번 글을 클릭하면 title이라는 스위치를 0으로 바꿔주고

1번 글을 클릭하면 title이라는 스위치를 1로 바꿔주고

2번 글을 클릭하면 title이라는 스위치를 2로 바꿔주고

그러면 의도한 기능이 완성되겠군요.

 

근데 지금 글제목들이 map 반복문으로 복잡하게 생성되어있기 때문에

반복문 무서워할까봐 반복문 없앤 버전으로 한번 먼저 시도해봅시다. 

 

 

 

 

설명하다
 
function App (){
  let [title, setTitle] = useState(0);
  return (
    <div>
      <button onClick={()=>{ ? }}> 0번글 </button>
      <button onClick={()=>{ ? }}> 1번글 </button>
      <button onClick={()=>{ ? }}> 2번글 </button>
      <Modal 어쩌구/>
    </div>
  )
}

버튼 3개를 만들어봤는데 이걸 각각의 글제목이라고 간주하고 여기에 코드를 짜보도록 합시다. 

0번 글을 누르면 title이라는 state를 0으로 바꿔주면 어떻게하죠? 

 

 

 

설명하다
 
function App (){
  let [title, setTitle] = useState(0);
  return (
    <div>
      <button onClick={()=>{ setTitle(0) }}> 0번글 </button>
      <button onClick={()=>{ setTitle(1) }}> 1번글 </button>
      <button onClick={()=>{ setTitle(2) }}> 2번글 </button>
      <Modal 어쩌구/>
    </div>
  )
}

이러면 될듯요 매우 쉽습니다.

그럼 이제 버튼 누를 때 마다 state가 잘 바뀝니다.

state가 바뀌면 모달창안의 제목도 알아서 잘 바뀌고요.

이제 연습은 끝났고 map 반복문안에 있는 제목도 저거랑 비슷하게 수정하면 될듯요 

 

 

 

저는 어떻게 했냐면

 

 

 

 

 

Q. state를 자식컴포넌트에 만들어버리면 props 전송안해도 되지않나요?

A. 맞습니다. title같은 state도 자식컴포넌트 안에 만들어보면 편할듯요? 

하지만 지금 title이라는 state는 App도 쓰고 Modal도 쓰고 있습니다.

그렇게 다양한 컴포넌트에서 쓰이는 state는

컴포넌트들 중 최고로 높은 부모에게 만들어놔야합니다. 

 

왜냐면 state는 부모 → 자식 전송만 가능하니까 그렇습니다. 

state를 자식에 만들어놨는데 갑자기 부모가 그게 필요해지면 어떻게 할 방법이 없으니까요. 

생각하기 귀찮으면 그냥 대부분 App 컴포넌트안에 만들면 됩니다. 

 

 

 

 

오늘 요약 :

1. 그래서 UI만드는 3-step 외워주면 알아서 뭐든 만들 수 있습니다.

이제 저에게 그만 물어보고 알아서 만들도록 합시다. 

 

2. state는 state를 사용하는 컴포넌트 중 최고 부모에 만들어놓아야합니다.

 

3. 뇌를 비우고 코드 따라치기만 했던 분들은 

오늘 했던거 싹 지우고 3일 후에 답보지말고 다시 만들어봅시다. 

내가 직접 생각해서 만들어봐야 공부라고 할 수 있습니다. 

 

 


import {useState} from 'react'
import './App.css';


function App(){
  let [글제목,글제목변경] = useState(['남자 코트 추천','강남 우동맛집','파이썬독학']);
  let [ 따봉, 따봉변경 ] = useState(0);
  let [modal,setModal] = useState(false);
  let [title,setTitle] = useState(0);
 
  return (

    <div className="App">
      <div className="black-nav">
        <h4>ReactBlog</h4>
      </div>
     {
      글제목.map(function(a,i){
        return (
          <div className='list' key={i}>
            <h4 onClick={()=>{setModal(true); setTitle(i)}}>  {글제목[i]}
              <span onClick={()=>{따봉변경(따봉+1)}}>👍</span>{따봉}
            </h4>
            <p>2월 17일 발행</p>
          </div>
            )}
        )
      }
   



    {
          modal == true ?  <Modal title={title} Modal color={'skyblue'} Modal 글제목={글제목}/> : null
        }

     


      <button onClick={ ()=>{
      let copy = [...글제목];
      copy.sort((a, b) => b.localeCompare(a)); // 역순 정렬을 위한 비교 함수
      글제목변경(copy)
    } }> 역순 정렬버튼 </button>


       <button onClick={ ()=>{
      let copy = [...글제목];
      copy.sort();
      글제목변경(copy)
    } }> 정렬버튼 </button>
 
     

      <button onClick={ ()=>{
       let copy = [...글제목];
        copy[0] = '여자코트 추천'
        글제목변경(copy);
        }} > 글수정</button>



     
     


    </div>
  );
}


function Modal(props){
  return (
    <div className="modal">
      <h4>{ props.글제목[props.title] }</h4>
      <p>날짜</p>
      <p>상세내용</p>
      <button>글수정</button>
    </div>
  )
}



export default App;