• React

[React] React hook basic

man_on 2021. 10. 21. 00:14
반응형

 

 

 

     


     

     

     

     


    Data binding

     

     

    JSX에서 데이터바인딩하기

     

    데이터 바인딩?

    자바스크립트 데이터를 HTML에 꽂아넣는 작업을 뜻한다.

     

    > 변수를 만들어서 넣기

     { } 중괄호에 넣어서 온갖곳에 변수 집어넣기 가능하다.

    import React, { useState } from "react";
    
    let data = "안녕";
    function app() {
      return (
        <div className="App">
          <div className="black-nav">
            <div>{data}</div>
          </div>
        </div>
      );
    }
    
    export default app;

     

    > html에 스타일 직접 넣기

      { } 중괄호에 넣어서 { 속성명 : '속성값'} 속성명은 camelcase로 입력해야된다.

     <div style={{ color: "red" }}>{data}</div>

     보기싫으니까 변수명에 넣어서 사용하거나 css파일에서 하도록 하자.

    let data = { color : 'red'}
    
    <div style={data}>

     

     

     

     

     

     

     


     

     

     

     

     

    State / useState

     

     

    중요한 데이터는 state로 저장한다.

     

    state를 쓰는이유?

     : 변수가 변경될 때 자동으로 관련된 html의 재렌더링을 원할때 사용한다.

       리엑트는 state가 수정이 일어나면 state가 포함된 html을 자동으로 재렌더링 해준다. (새로고침 없이 스무스하게~)

      : state는 instance 기반 단위로 나누어져있다.

     

    ES6 destructuring 문법

    > array안에 있는 데이터를 변수에 저장한다.

    import React, {useState} from 'react';
    
    let [a,b] = useState('저장', '저장변경')
    // a= 저장, b=저장변경

     

     

    state에는 array, object 아무거나 다 넣을 수 있다.

    이때도 역시 중괄호를 사용한다.

    let [ name, namechange ] = useState(기본값);
    
    <div> { name } </div>

     


     

     

    useState로 state를 변경한다.

     

    let [ name, namechange ] = useState(기본값);

     

     

    버튼기능은 onClick으로 만든다.

    <div onClick={실행할 함수}>
    
    //함수
    <div onClick={어디서만들어놓은함수명}>
    <div onClick={ () => {실행할 코드} }>

     

     

    > 2가지로 나타낼 수 있다.

     1. 다음상태를 추가

     2. 업데이트할 상태추가(함수로)

      const [number, setNumber] = useState(0);
      
      //다음상태
      const Decrease = () => {
        setNumber(number - 1);
      };
      
     //상태 업데이트
      const Increase = () => {
        setNumber((prevNumber) => prevNumber + 1);
      };

     

    값을 변경할때는 지정된 변경함수를 쓰는게 포인트다.

    onClick = { ( ) => { } }  이벤트 핸들러를 달아어 사용한다.

    중괄호안에 { state변경함수 (대체할데이터) } 를 넣어준다.

    소괄호내에있는 데이터로 완전히 대체된다. (소괄호안에는 깔끔하게 변경할 값만 넣어줘야한다.)

    function app() {
    
      let [like, likeChange] = useState(0);
      //like=state , likeChange=state변경함수
      return (
            <h3 onClick={() => {likeChange(like + 1);}}>  
            {post} <span>🙉</span> {like}
            </h3>

     

    state는 등호나 직접수정이 불가능해서 state변경함수를 사용해야 한다.

    state를 아예 대치해서 변경해야된다는 뜻이다.

    function 제목바꾸기 () {
     state변경함수(대치,변경)
    }

     

    1. 쉽게 바꾸려면 바꿔치기할 새로운 array를 통째로 넣는다.

    function 제목바꾸기 () {
     state변경함수(['제목변경', '제목2', '제목3'])
    }

     

    2.  state 변경함수 만드는 방법

    function 제목바꾸기고급버전 () {
     let newArray = [...글제목];    //state복사본을 새변수에 저장한다.
     newArray[0] = '제목변경'        //복사본을 조작한다.
     글제목변경(newArray);            //변경된거를 변경함수에 집어넣는다.
    }
    
    <div onClick={제목바꾸기고급버전}> 버튼 </button>

     

     > array, object자료형에서 = 등호로 복사하면 별개의 자료형이 아니고 값을 공유하게된다. (javascript reference data type)

        따라서, shallow/deep copy를 해줘야한다.

         let 새로운array = [...원본array];

     

         ...은 뭐임?

         1. 괄호벗길때 사용한다.

         2. 괄호벗기고 완전 독립적인 array를 만들어준다.

     

        복사본 매번 반듬?

        : 복사본은 reference 자료형들만 (array, object 요런거) 

         문자, 숫자, true/false 이런건 직접수정하면됨

     

     

     


     

     

    Input  : 사용자가 입력한 글을 변수에 저장하기

     

      > input값 저장흐름 ( <textarea>, <select> 태그들도 동일 )

       1.  값 저장할 빈 state생성

       2.  input 태그에 onChange 이벤트 핸들러를 단다. ( onChange 입력할 때 특정함수 동작시킬 때 사용한다.)

            e.target.value ?

           ( js 문법. e.target = '지금 이벤트가 동작하는 html요소' / .value = 'input에 입력한 값' )

            

       

    function App () {
      let [입력값, 입력값변경] = useState(' ');
      
      return (
        <div>
          <input onChange = { (e) => { 입력값변경(e.target.value) }} />
        </div>
      )
     }
     
     //확인할 때 콘솔창 찍어보기 {(e) => {console.log(e.target.value)}

     

     

     

    > 여러개의 input 상태관리하기 ( 객체에서 새 항목 추가 )

    export const InputSample2 = () => {
      const [input, setInput] = useState({
        name: '',
        nickname: '',
      });
      const { name, nickname } = input;
    
      const onChange = (e) => {
        const { name, value } = e.target;
        setInput({
          ...input,
          [name]: value,
        });
      };
    
      const onReset = (e) => {
        setInput({
          name: '',
          nickname: '',
        });
        nameInput.current.focus();
      };
      const nameInput = useRef();
    
      return (
        <>
          <input
            placeholder="name"
            onChange={onChange}
            name="name"
            value={name}
            ref={nameInput}
          />
          <input
            placeholder="nickname"
            onChange={onChange}
            name="nickname"
            value={nickname}
          />
          <button onClick={onReset}>Reset</button>
        </>
      );
    };

     

     

     

     

     

     > 배열에 항목 추가하기 (클릭하면 게시물 추가시키기)

       - push, splice, sort 등의 함수로 기존의 state를 변경하려면 state를 복사해서 변경해준다.

       - 배열의 불변성을 유지하면서 항목을 추가하려면

          1. spread 연산자로 복사한 후 새항목을 추가한다.

     

    fucntion app() {
     let [글제목, 글제목변경] = useState(['title1', 'title2', 'title3']);
     let [입력값, 입력값변경] = useState('');
     
    //글제목변경하는 함수만들어서 button에 넣어준다.
     funtion pushName() {
       let newArray = [...글제목];
       newArray.unshift(입력값);
       글제목변경(newArray);
    }
     
     return (
       <div> 
       	<input onChange={ (e) => {입력값변경(e.target.value}} />
        <button onClick={ ()=> {pushname} >저장</button>
     )

     

     

     


     

     

    각각 다른 모달창 제작

     

      > 버튼마다 다른 모달창제목 뜨도록 제작하기

       1. 몇번째 제목 눌렀는지 state로 저장한다. (기본값0)

       2. state가 0일때는 0제목, 1일때는 1제목 출력해준다. (state달라지면 UI도 달라지게 만든다.)

     

     

      > UI만드는 법은 다 똑같다.

       1. state하나 만든다.

       2. state가 ~한 상태일때 이런 UI보여줘~ 

      (3. 추가: 버튼 누르거나할 땐 state를 이렇게 바꿔줘 )

     

     

    의식의 흐름

    // 처음에 버튼3개로 시작해본다.
    
    function App() {
    	let [글제목, 글제목변경] = useState(0);
        let [누른제목, 누른제목변경] = useState(0);
        return (
        	<div>
              <button onClick={() => { 누른제목변경(0) }}버튼1</button>
              <button onClick={() => { 누른제목변경(1) }}버튼2</button>
              <button onClick={() => { 누른제목변경(2) }}버튼3</button>
              ...
              
              <Modal 글제목={글제목} 누른제목={누른제목} />
            </dvi>
        )};
        
        
     function Modal (props) {
        return (
           <p> 제목 {props.글제목[props.누른제목] } </p>
           ...

     

    글의 제목누르면 state가 변경되게 만들어본다.

    누른제목변경 : 반복문 돌때 차례로 0,1,2...되는 함수 index (파라미터에 두번째로 추가한다)

     

    function App() {
      return (
       <div>
       ...
        {글제목.map (function(a, i) {
           return (
           <h3 onClick = { () => { 누른제목변경(i) }}> {a}
           //

     

     

     

     

     

     


     

     

     

     

     

     

    Component / map

     

     

     

    html을 한단어로 치환하는 Component

     

     

      > 어떤 html들을 component로?

       : 반복출현하는 애들을 재사용 하고 싶을 때

         긴코드를 축약하고 싶을 때 

         내용이 자주 변경되는 애들

         기능별로 나누고 싶은 애들

     

     

     > 단점 ? 

         : props를 이용해서 state를 component까지 전해줘야 사용이 가능하다.

       

     

    > 만드는 방법?

    1. function을 이용해서 함수를 하나 만들어준다.

    2. 그 함수 안에 return () 안에 원하는 HTML을 담는다.

    3. 원하는 곳에서 <함수명 />이라고 사용했을 때 아까 축약한 HTML이 등장한다.

     

     

     

     

     

     

    예제) 클릭하면 보이는 모달창 만들기

      : 리엑트 중괄호내에서 if문같은거 못쓰니까 삼항연산자를 이용한다.

       ( 조건식 ? 조건식참일때실행코드 : 거짓일때실행코드 )

       텅빈 html을 나타낼때는  null을 쓴다.

     

     

      > 구현 과정

       0. Modal Component를 만든다.

       1. 모달창 보이는 / 보이지않는 상태를 저장할 state를 만든다.

       2. 삼항연산자 이용 && 사용해서 true일때 모달창 보이게 해준다. (false일땐 null)

       3. 열기버튼 눌렀을 때 모달창 보이게 해준다. (클릭 on off 연속 > !modal )

      

     

    * 내용이 달라질때는 삼항연산자 사용

      null 값 나타내고 싶을 땐 and 연산자 사용

    //1
    let [modal, modalChange] = useState(false);
    
    //2
    { modal === true ? <Modal /> : null }
    { modal === true && <Modal /> }
    
    //3
    <button onClick = { () => {modalChange(!modal) } />

     

     

     

     

     

     

     

    map함수

     

     : 기존 array 변형시켜서 새로운 array를 만들어준다.

     

       중괄호 { } 안에는 변수, 함수 이런것만 입력가능하다.

       for문 이런거 못쓰니까 map사용한다. ( array에 붙일 수 있는 일종의 내장함수 )

     

    let array = [ 2,3,4 ];
    
    {
      array.map (콜백함수()=>{
         return ~반복시킬 html~
    });
    //array의 자료갯수만큼 실행된다.

     

     

    > map은 원본을 변형시키지않는다.

       그러므로 새로운 array에 담아준다.

    > 콜백함수에 파라미터를 하나 추가하면 array안의 데이터들을 하나씩 출력해준다.

    //1.원하는 자료에 map을 붙여준다. 
    //2.return안에 반복원하는 html을 넣어준다.
    
    let newArray = 어레이.map (function(a) {
      return a*10
    });

      

     

    * key = {i} 

       키값 지정해줘야 에러안뜬다!

       키값이 있어야 어떤 element를 지칭하고 있는지 정확히 인식하여, 새로운 항목이 추가되거나 제거될때 효율적으로 업데이트(render)가 된다.

       id 값이 없으면 index로 키값을 지정할 수 있지만, 비효율적으로 업데이트 된다.

     

     

    > map함수 예제

    더보기
    //부모 컴포넌트
    //shoes데이터의 i번째 데잍터를 받아오고 싶을 때, {shoes[i]} 혹은 {a}를 해준다.
    
    function App() {
      let [shoes, shoes변경] = useState(data);
    
      return (
          {shoes.map((a, i) => {
            return <Shoes shoes={shoes[i]} i={i} key={i} />;
          })}
    /* 상품이미지들 데이터바인딩하기
    글자 중간에 변수를 넣고싶으면 '문자' + 변수 + '문자' */
    
    import React from "react";
    
    //props로 부모의 데이터 받아온다.
    function Shoes(props) {
      return (
        <div className="container">
          <div className="row">
            <div className="col-md-4">
              <img
                src={"https://codingapple1.github.io/shop/shoes" + (props.i + 1) + ".jpg"}
                width="100%"
                alt={props.Reacti}
              />
              <h5>{props.shoes.title}</h5>
              <p>
                {props.shoes.content}&{props.shoes.price}
              </p>
            </div>
          </div>
        </div>
      );
    }
    export default Shoes;

     

     

     

     


     

     

     

     

    Props

     

     

     

     

    Props  :  자식이 부모의 state를 가져다 쓰고 싶을 때

     

     

      부모의 state변수는 props로 자식까지 state를 전송해줘야 사용가능하다.

     

     

    1. <자식componame    작명={stateName}  />

    2.  자식 component 선언하는 function안에 파라미터 생성한다.

     

    //부모
    //{변수명} or '텍스트'  둘다가능하다.
    <Modal 전송할이름={state명} />
    
    //props여러개 가능하다.
    <Modal 이런거="이런거" 저런거="저런거" />
    
    
    //자식
    function Modal (props) {             //props에 모든 props데이터 담겨있다.
     return (
       <h2> {props.글제목[0]} </h2>        //props에서 필요한 데이터만 사용한다.

     

     

    props쓰기 귀찮는데 자식component에다가 바로 꽂아넣으면 안되나?

     : 데이터는 항상 위에서 아래로 흘러야한다.

       옆 자식이 데이터필요하면 부모로 올려보냈다가 다시 옆자식에게 줘야하잖아..데이터 역방향으로 전달시키면 props보다 더귀찮아진다..

      그러니까 state만들때는 state를 필요로하는 컴포넌트 중 가장 최상위 컴포넌트에 보관해야한다.

     

     

     

     


     

     

    Children Props

    단순히 shell 역할만하는 componet를 만들고 싶을 때

     

     

    ex) box의 css

    Expenseitem 컴포넌트에서 card컴포넌트의 css를 사용하고 싶을 때 Card컴포넌트로 감싸주면

    <Card></Card> 내부에있는 요소들의 classname props로 넘겨줄 수 있다.

    function Expenseitem(props) {
      return (
        <Card className="expense-item">
          <ExpenseDate date={props.date} />
          <div className="expense-item__description">
            <h2>{props.title}</h2>
            <div className="expense-item__price">${props.amount}</div>
          </div>
        </Card>
      );
    }

     

    Card.js 컴포넌트 생성

    1. {props.children}

    2. Card 컴포넌트의 classname 'card '와 props로 받은 Expenseitem에서 Card안에 요소들의 classname을 결합하여 css를 씌워줄 수 있다. ( "card " 에서 띄어쓰기 해주기! )

     

    import "./Card.css";
    
    function Card(props) {
      const classese = "card " + props.className;
      return <div className={classese}>{props.children}</div>;
    }
    
    export default Card;
    .card {
      border-radius: 12px;
      box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
    }

     

     

     

     


     

     

     

     

     

    조건부 렌더링

     

     

     

    React에서 조건부 렌더링 3가지 방법

     

    [기존]

            {filteredExpenses.map((expense) => (
              <ExpenseItem
                key={expense.id}
                title={expense.title}
                amount={expense.amount}
                date={expense.date}
              />
            ))}

     

     

    1. 삼항연산자

            <ExpensesFilter dataSave={dataSave} selected={filteredYear} />
            {filteredExpenses.length === 0 ? (
              <p>No expense found.</p>
            ) : (
              filteredExpenses.map((expense) => (
                <ExpenseItem
                  key={expense.id}
                  title={expense.title}
                  amount={expense.amount}
                  date={expense.date}
                />
              ))
            )}

     

     

    2. &&

            {filteredExpenses.length === 0 && <p>No expense found.</p>}
            {filteredExpenses.length > 0 &&
              filteredExpenses.map((expense) => (
                <ExpenseItem
                  key={expense.id}
                  title={expense.title}
                  amount={expense.amount}
                  date={expense.date}
                />
              ))}

     

     

     

    3.변수에 추가

       return 전에 변수에 로직 추가해놓고 JSX코드에서 변수만 깔끔하게 넣어준다.

      let expensesContent = <p>No expense found.</p>;
      if (filteredExpenses.length > 0) {
        expensesContent = filteredExpenses.map((expense) => (
          <ExpenseItem
            key={expense.id}
            title={expense.title}
            amount={expense.amount}
            date={expense.date}
          />
        ));
      }
      
        return (
           {expensesContent}
         )

     

     

     

     

     

    삼항연산자 vs &&

    //삼항연산자
           {isEditing ? (
            <button onClick={startEditingHandler}>Add new Expense</button>
          ) : (
            <ExpenseForm
              onSaveExpenseData={saveExpenseDataHandler}
              onNewForm={startEditingHandler}
            />
          )}
    //&&연산자
          {isEditing && (
            <button onClick={startEditingHandler}>Add new Expense</button>
          )}
          {!isEditing && (
            <ExpenseForm
              onSaveExpenseData={saveExpenseDataHandler}
              onNewForm={startEditingHandler}
            />
          )}

     

    반응형

    '• React' 카테고리의 다른 글

    [React] styled-components / SASS / CSS Module  (0) 2021.10.24
    [React] Router  (0) 2021.10.24
    [REACT] State / Event  (0) 2021.09.04
    [REACT] Component / Props / Mock data  (0) 2021.09.01
    [REACT] JSX / Component  (0) 2021.08.30