[신세계I&C KDT][React] #47 React.js #2 props, useState, useRef (0628, 0701)

박현아·2024년 7월 2일
0

신세계아이앤씨 KDT

목록 보기
51/56

1. Image 사용하기

  • 반드시 src 폴더에 저장하고
    import 해서 사용 권장.
  • 실습
    1- src/assets 폴더 생성
    2- 이미지 저장
    3- import 해서 이미지 사용

예>
import daum from './assets/daum.png';

< img src={daum} width="100" height="100" />

2. props

1) 용도

  • 화면 레이아웃이 중첩된 형태로 되어있고, 부모 컴포넌트에서 자식 컴포넌트에게 데이터를 전달할 때 사용하는 방법 (단방향)

2) 특징

  • 단방향 (부모에서 자식으로만 전달 가능)
  • 전달되는 데이터 종류 제한이 없음
  • 필수 아님

3) 문법

(1) 속성 (property) 이용

< Child key={값|변수} key2={값|변수} />
function Child(파라미터) { <== JSON으로 전달됨
}
function Child({key1, key2}) {}
function Child({key1, key2=값}) {}

(2) body 이용

< Child>
값 (문자열, JSX)
< /Child>
function Child(파라미터) { <== JSON으로 전달됨
body는 파라미터.children으로 얻음
}

3. 이벤트 처리

1) 개요

  • 이벤트 핸들러 (이벤트 함수)는 함수 컴포넌트 안에서 정의함
    예>
    // 함수 컴포넌트
function App() {
    
    // 이벤트 함수
    function go () {}
    
    return(
    	// JSX
    );
}
  • JSX에서 이벤트 처리는 카멜표기법을 사용해야된다

2) 기본 문법 2가지

(1) 이벤트함수명 이용

onClick={이벤트함수명}
onClick={go}

  • 이벤트객체는 자동으로 전달됨

(2) arrow 함수 이용

onClick={arrow 함수}
onClick={()=> go(값)}

  • 명시적으로 함수 호출
  • 이벤트객체는 자동으로 전달 안 됨. 명시적으로 전달해야 된다
    예> < button onClick={(e)=>handleEvent1(e)}>OK3< /button>

3) 이벤트 객체 사용 가능

  • e.preventDefault();
  • e.stopPropagation();

4) 계층구조 이벤트 처리

  • 부모의 있는 함수를 자식에게 전달 가능하다.
    이 방법을 이용하면 자식이 부모에게 데이터 전달이 가능해진다. ( 계층적 이벤트 + props 이용 )
    props
    부모 ------------------------> 자식
    <------------------------
    계층적이벤트 + 파라미터

4. 배열 반복

  • map 기억하긔
 /////////////////////////////////////
  const userList = [{username:"홍길동1",age:20, address:"서울1"},
                    {username:"홍길동2",age:50, address:"서울2"}, 
                    {username:"홍길동3",age:60, address:"서울3"}  
                   ];

  // js 
  var result = userList.map(function(data, idx){
       console.log(data,idx);
       return data;
  });

  var result = userList.map((data, idx)=>{
    return data;
  });

  var result = userList.map((data, idx)=>data);

  console.log(result);

  /////////////////////////////////// 

// 컴포넌트
function Avatar({username, age, address}){

  return(
     <span className="Avatar">
         이름:{username}, 나이:{age}, 주소:{address}
     </span>
  );
}
function App() {

  return (
    <div className="App">
        <h2>1.배열의 첨자이용해서 개별접근</h2>
        회원1: 이름:{userList[0].username}, 나이:{userList[0].age}, 주소:{userList[0].address}<br></br>
        회원2: 이름:{userList[1].username}, 나이:{userList[1].age}, 주소:{userList[1].address}<br></br>
        회원3: 이름:{userList[2].username}, 나이:{userList[2].age}, 주소:{userList[2].address}<br></br>

        <h2>2.Avatar 컴포넌트 이용</h2>
        회원1: <Avatar {...userList[0]} /><br></br>
        회원2: <Avatar {...userList[1]} /><br></br>
        회원3: <Avatar {...userList[2]} /><br></br>


        <h2>3.배열의 첨자 반복</h2>
        {/*
             var result = userList.map(function(data, idx){
                console.log(data,idx);
                return data;
            });

            var result = userList.map((data, idx)=>{
              return data;
            });

            var result = userList.map((data, idx)=>data);

         */}
        {
               userList.map((data, idx)=>{
                  return <div key={idx}>회원{idx+1}: 이름:{data.username}, 나이:{data.age}, 주소:{data.address}</div>
               })
        }
         <h2>4. Avatar 반복1</h2>
         {
               userList.map((data, idx)=>{
                  return <> 
                           <Avatar key={idx}  username={data.username}  age={data.age}  address={data.address}/><br></br>
                         </>
               })
        }
        <h2>4. Avatar 반복2</h2>
         {
               userList.map((data, idx)=>{
                  return <> 
                           <Avatar key={idx}  {...data} /><br></br>
                         </>
               })
        }   

    </div>
  );
}

export default App;

5. hooks

1) 개요

이전에는 클래스에서만 사용할 수 있는 기능이 있었음
React 16.8 이후부터는 클래스에서만 사용했던 기능을 함수에서도 사용할 수 있도록 지원됨 ==> hooks

2) 종류

  • useState
  • useRef
  • useEffect
  • useContext
  • useMemo
  • useCallback

주의할 점은 반드시 최상위 함수 (컴포넌트) 에서만 사용 가능하고 일반 함수, 반복문, 조건문 등에서는 사용 불가

6. 상태값 (state) 관리

1) 개요

props는 자식이 변경이 가능할까? 불가능. read only 이다
state는 변경이 가능하고 변경이 되면 자동 재랜더링이 된다 ⭐
state에 저장되는 값은 JS의 모든 데이터 가능 (문자, 숫자, JSON, 배열 등)

2) 사용 방법

(1) import

import { useState } from 'react';

(2) 함수 컴포넌트 안에서 useState를 사용

const [ 변수, set메서드 ] = useState(변수초기값);
변수를 변경하기 위해서는 반드시 set 메서드를 사용해야 된다
const [ num, setNum ] = useState(0);
const [ arr, setArr ] = useState([]);
const [ user, setUser ] = useState({id:'', pw:''};

(3) 값 변경

반드시 set 메서드를 써서 값을 변경해야된다
setNum(num+1);

(4) JSX에서 state 사용

{ 변수 }
예> { num }

3) 배열 또는 json 데이터인 경우의 state 처리 ⭐

  • 반드시 불변객체로 작성해야된다
    불변객체? 배열 또는 JSON 내의 값을 변경하는 방식이 아닌, 값을 변경한 새로운 배열 또는 JSON을 만들어서 state에 설정하는 것을 의미
  • 구현 방법

(1) 배열 또는 JSON 복사본을 만듦

=> 가장 쉽게 복사본을 만드는 방법은 spread 연산자를 이용하는 것

(2) 새로 생성된 배열 또는 JSON 수정

(3) state에 새로 생성된 배열 또는 JSON을 저장

4) state + < input> 사용시 구현 패턴

  • 사용자가 입력하는 값은 기본적으로 html 태그의 value 속성에 저장됨.
    이 때, value={state} 형식으로 사용하면, 사용자가 입력하는 값이 화면에 랜더링 되지 않는다. 따라서 value 값과 state 값을 입력값으로 일치시키기 위해서 onChange 이벤트로 state 값을 변경시켜주는 코드가 필요하다
import logo from './logo.svg';
import './App.css';
import { useState } from 'react';


function App() {

  const [userid, setUserid] = useState('');

  function handleEvent(e) {
    setUserid(e.target.value);
  }


  return (
    <div className="App">
      <h1>사용자입력 태그 + state 사용</h1>
      입력값 : {userid}<br></br>
      아이디 : <input type="text" name="userid" value={userid} onChange={handleEvent}/>
    </div>
  );
}

export default App;

7. ref

1) 개요

  • 일반적으로 JSX 참조할 때 사용됨
  • 드물지만 일반값 저장도 가능

2) 사용방법

(1) import { useRef } from 'react';

(2) useRef 사용

let xxx = useRef(기본값);

(3) JSX에 ref 설정

예> < input ref={xxx} />
< Child ref={xxx} />
< Child ref={xxx=>xxx} />

(4) JSX 접근 방법

xxx.current 속성으로 참조 가능

3) 부모에서 자식을 참조 가능

https://react.dev/reference/react/forwardRef

  • < Child ref={xxx} userid="홍길똥"
  • ref 속성은 미리 정의된 속성이기 때문에 Child 자식 컴포넌트에서 props로 ref를 전달할 수 없음
  • Child 컴포넌트에서 App인 부모에서 전달하는 ref 를 얻기 위해서는 forwardRef() 메서드를 사용해야 되고 props와 ref를 따로 얻어야 된다
const Child=forwardRef(  
		    (props, ref)=> {    // props와 ref를 따로 받아야 됨.
		     console.log(props, ref);
		    return (
		      <div className="Child">
			<h2>Child컴포넌ㅌ</h2>
			아이디:<input  />
		      </div>
		     );
		  } );

4) 부모에서 자식의 메서드 호출

https://react.dev/reference/react/useImperativeHandle

  • 자식 컴포넌트
  const Child=forwardRef(  
	    (props, ref)=> {
	     console.log(props, ref);

	      const input_ref = useRef(null);

	    // 방법1: 외부에서 작성된 함수 선언식 이용 
	    useImperativeHandle(ref, ()=>({open2})); // ({함수명,함수명2})
	     //App에서 호출
	     function open2(){
	       console.log("open 메서드");
	     }

	     // 방법2: return {} 안에서 작성된 함수 선언식 이용 
	     // https://react.dev/reference/react/useImperativeHandle 참조할 것.
	     useImperativeHandle(ref, ()=>{
		return {
		  open(x){
		    console.log("open 메서드 >>>>>>>>>>>>>>", x);
		  },
		  close(){
		    console.log("close 메서드 >>>>>>>>>>>>>>");
		  },
		  input_value(){
		    return input_ref.current.value;
		  }
		}
	     });


	    ////////////////////////////////////
	    return (
	      <div className="Child">
		<h2>Child컴포넌ㅌ</h2>
		mesg:{props.mesg}<br></br>
		아이디:<input  ref={input_ref}/>
	      </div>
	     );
	  } );
	  
	  export default Child;
# 부모 컴포넌트
 function App() {

  const xxx = useRef(null);

  function handleEvent(){
    // console.log("Child input값 출력:", xxx.current.value);
    console.log("Child input값 출력:", xxx.current.input_value());

    //Child open 메서드
    xxx.current.open(100);
    xxx.current.close();
  }

  return (
    <div className="App">
      <h2>App 컴포넌트</h2>
      <Child ref={xxx} mesg="hello" /><br></br>
      <button onClick={handleEvent}>Child의 input값 얻기</button>
    </div>
  );
}

export default App;

5) 모달 창

https://developer.mozilla.org/ko/docs/Web/HTML/Element/dialog 참고

0개의 댓글