ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 개발공부 34일차 [유데미 리엑트 강의]
    개인공부 2023. 2. 27. 23:22

    JSX (리엑트에서 주로 사용하는 표현식)

    리엑트는 자바스크립트 기반으로 동작한다.

    컴퍼넌트 만들기

    1. 헤더역할을 할 컴퍼넌트 먼저 만든다.
      src디렉토리 아래에 파일을 하나 생성한다. MyHeader.js
    2. MyHeader.js 파일안에 파일을 내보낼 수 있도록 써주고
    export default MyHeader;

       3. app.js안에 상단에 불러와준다.

    import MyHeader from './MyHeader'

       4. 태그를 넣어줄 곳에 MyHeader을 넣어준다.

    return (
        <div className="App">
          <MyHeader />
         //여기에 넣어준다!
          <header className="App-header">
            <h2>안녕 리엑트 {name}</h2>
          </header>
        </div>
      );
    }

    css주기

     

    htnl에서는 css를 줄때 class를 class = “ “ 이렇게 줬었는데

    jsx에서는 class가 자바스크립트의 예약어이기 때문에 사용이 불가하다.

    css를 줄때는 className= “ “ 으로 줄 수 있다.

     

    css파일도 import로 불러 올 수 있다.

    import './App.css';

    inline 스타일링

    // import './App.css';
    import MyHeader from './MyHeader'
    
    
    function App() {
      let name = "유리"
    
      const style = {
        App: {
          backgroundColor: "black",
        },
        h2: {
          color: "red",
        },
        bold_text: {
          color: "green",
        },
      }
    
      return (
        <div style={style.App}>
          <MyHeader />
          <h2 style={style.h2}>안녕 리엑트 {name}</h2>
          <b style={style.bold_text} id="bord_text">React.js</b>
        </div>
      );
    }
    
    export default App;

    파일을 따로 이용하지 않고 함수 안에 style을 넣고 각 태그에 style을 줘서 css를 줄 수 있다.

     

    값을 렌더링 하는방법

    const number = 5;
    
      return (
        <div style={style.App}>
          <MyHeader />
          <h2 style={style.h2}>안녕 리엑트</h2>
          <b style={style.bold_text} id="bord_text">
            {number}는 : {number % 2 === 0 ? "짝수" : "홀수"}
             {/* 5는 : 홀수 */}
          </b>
        </div>
      );
    }

    { }값에는 숫자, 문자, 함수, 조건식을 넣을 수 있는데 false, [] 등 숫자나 문자열이 아닌건 렌더링이 되지 않는다.

     

    State

    컴퍼넌트가 갖는 테마처럼 계속 값이 바뀔 동적인 데이터이고 상태를 바꾸는 등의 관리는 이걸 컴퍼넌트가 직접 관리하게 된다.

    import React, { useState } from "react";
    
    const Counter = () => {
      // o에서 출발
      // 1씩 증가하고
      // 1씩 감소하는
      // count상태
      console.log("counter 호출!")
    
      const [count, setCount] = useState(0);
      //useState라는 리엑트의 메서드는 배열을 반환하고 배열의 비구조화 할당을 통해서 
      //0번째의 인덱스를 count로 1번째의 인덱스를 setCount로 받아왔다는 의미setCount 
      //= count라는 상태를 변화시키는 상태변환 함수 useState의 (0)은 count의 
      //초기값으로 사용이 된다.
      //useState로 상태를 만들면 count라는 이름으로 상태의 값을 불러올 수 있는거고 
      //setCount라는 상태로 count를 변화시킬 수 있는거고 (0)초기값을 여기에 넣어준다.
    
      const onIncrease = () => {
        setCount(count + 1)
      }
      //count의 상태가 1이였을때 +버튼을 누르면 onIncrease라는 인자가 수행이 된다.
      //setCount가 (1 + 1)이 전달되어 2로 바뀌고 이 값이 count로 전달이되어 
      //count값이 2로 바뀌게 되고 <h2>{count}<h2>의 count값도 2로 바뀌게 되어 
      //화면에도 2로 바뀌게 된다.
    
      const onDecrease = () => {
        setCount(count - 1)
      }
      return (
        <div>
          <h2>{count}</h2>
          <button onClick={onIncrease}>+</button>
          {/* html에서는 onclick = 'onIncrease()'사용했지만 
          리엑트에선 {}로 사용해야한다. */}
          <button onClick={onDecrease}>-</button>
        </div>
      )
    }
    //count가 바뀔때마다 Counter라는 함수가 반환을 다시 한다 라고 생각 할 수 있다.
    
    export default Counter;

    count가 바뀔때마다 Counter라는 함수가 반환을 다시 한다 라고 생각 할 수 있다.

    이런걸 리렌더링이라고 한다.

    리렌더링

    함수가 자신이 가지고 있는 상태가 변화하면 함수를 다시 호출한다.

    확인을 위해 console.log에 확인을 해보면 버튼을 눌러서 count값이 바뀔때마다 계속 호출이 뜨는걸 볼 수 있다.

    Props

    위내용의 count의 초기값을 0으로 지정해주는게 아닌 app.js가 전달하는 값으로 써야할때는 ?

    initialValue={ }로 전달 할 수 있다.

    return (
        <div>
          <MyHeader />
          <Counter initialValue={5} />
        </div>
      );
    }

    다만 전달해야할 값이 많을때는 저렇게 사용하게되면 코드가 길어질 수 있다.

    //App.js
    function App() {
      const counterProps = {
        a: 1,
        b: 2,
        initialValue: 5
      }
    
      return (
        <div>
          <MyHeader />
          <Counter {...counterProps} />
          {/* 객체 형식으로 counterProps가 전달되게 된다. */}
        </div>
      );
    }

    전달할 값을 따로 빼서 {…상수명}으로 전달 할 수 있다.

    이렇게 전달하면 객체형식으로 전달이 되어 받아서 사용할때도 {원하는값}으로 불러올 수 있다.

    import React, { useState } from "react";
    
    const Counter = ({ initialValue }) => {
      //props에 initialValue의 값만 가져다 쓸 수 있다.
    
      const [count, setCount] = useState(initialValue);
    
      const onIncrease = () => {
        setCount(count + 1)
      }
    
      const onDecrease = () => {
        setCount(count - 1)
      }
      return (
        <div>
          <h2>{count}</h2>
          <button onClick={onIncrease}>+</button>
          <button onClick={onDecrease}>-</button>
        </div>
      )
    }
    
    Counter.defaultProps = {
      initialValue: 0
    }
    //App.js에서 initialValue의 값이 지워지거나 찾지 못할때 undefined가 나오기때문에
    //대비해서 넣어주는거임. 만약 진짜 지워지거나 찾지 못할때 count의 초기값은 0으로 설정된다.
    
    export default Counter;

    이렇게되면 초기값을 직접 지정하지 않고 사용할 수 있다.

     

    count의 값이 홀수인지 짝수인지 알려주게 만들기

    OddEvenResult파일을 만들고 내보내준 후 Counter.js파일에 보여질 위치에 자식요소로 넣는다.

    return (
        <div>
          <h2>{count}</h2>
          <button onClick={onIncrease}>+</button>
          <button onClick={onDecrease}>-</button>
          <OddEvenResult count={count} />
        </div>
      )
    const OddEvenResult = ({ count }) => {
      //{count}라고 적은건 count는counter라는 컴포런트가 가지고 있기때문에 props로 가지고온거다.
      console.log(count)
      return <>{count % 2 === 0 ? "짝수" : "홀수"}</>
    }
    
    export default OddEvenResult;

    count의 숫자가 바뀔때마다 짝수인지 홀수인지 나타난다.

     

    만약 count를 넣지않고 않았을때에도 부모요소인 Counter이 리렌더 될때마다 자식요소도 리렌더되서

    count가 바뀌게되면 콘솔에 RENDER!이 계속 찍힌다.

    const OddEvenResult = () => {
      //{count}라고 적은건 count는counter라는 컴포런트가 가지고 있기때문에 props로 가지고온거다.
      console.log("RENDER!")
      //버튼을 누를때마다 RENDER이 찍히는걸 볼 수 있다.
      return <>{10 % 2 === 0 ? "짝수" : "홀수"}</>
    }
    
    export default OddEvenResult;

     

    컴퍼넌트를 컴퍼넌트 자체로 props할 수 있다.

    컴퍼넌트를 감쌀 파일을 만들고 props로 전체를 감쌀 수 있다.

    //Container.js
    const Container = ({ children }) => {
      return <div style={{ margin: 20, padding: 20, border: "1px solid gray" }}>
        {children}
        {/* div값을 감싼 children */}
      </div>
    }
    
    export default Container
    //App.js
    function App() {
      const counterProps = {
        a: 1,
        b: 2,
        initialValue: 5
      }
    
      return (
        <Container>
          <div>
            <MyHeader />
            <Counter {...counterProps} />
          </div>
        </Container>
      );
    }

    컴퍼넌트를 감쌀 Container파일을 만든 후 html을 감싸서 태그를 만든다.

    Container컴퍼런트의 자식요소(<MyHeader />, <counter><div>) 들은 {children}이라는 props로 전달하게 된다.

    {children}을 값처럼 활용을해서 style이 있는 div안에 넣어서 자식요소들이 div의 값을 다 받을 수 있다.

     


    React 기본 - 일기장 만들어보기!

    import { useState } from "react";
    
    const DiaryEditor = () => {
    
      const [author, serAuthor] = useState("")
    
    
      return <div className="DiaryEditor">
        <h2>오늘의 일기</h2>
        <div>
          <input value={author} />
        </div>
      </div>
    }
    export default DiaryEditor;
    1. { useState }를 사용하기 위해 import한다.
    2. author의 초기값을 “ “ 공백으로 지정을 해서 input에 값을 author로 지정을해서 아무리 입력해도 serAuthor인 상태변화함수가 실행되지 않아서 공란에서 바뀌지 않는다.
    import { useState } from "react";
    
    const DiaryEditor = () => {
    
      const [author, setAuthor] = useState("")
      const [content, setContent] = useState("")
    
      return <div className="DiaryEditor">
        <h2>오늘의 일기</h2>
        <div>
          <input
            name="author"
            value={author}
            onChange={(e) => {
              //값이 바뀌었을때 사용하는 이벤트
              setAuthor(e.target.value)
            }}
          />
        </div>
        <div>
          <textarea
            value={content}
            onChange={(e) => {
              setContent(e.target.value)
            }}
          />
        </div>
      </div>
    }
    export default DiaryEditor;

    onChange라는 이벤트를 이용해서 값이 입력됬을때 setAuthor로 내용이 들어가서 그값이 다시 author로 들어감으로써 input값이 입력된다.

     

    값이 들어가는 방식은 동일하기 때문에

      const [author, setAuthor] = useState("")
      const [content, setContent] = useState("")

    위 방식을 하나로 합칠 수 있다.

    import { useState } from "react";
    
    const DiaryEditor = () => {
    
      const [state, setState] = useState({
        author: "",
        content: "",
      })
    
    
      return <div className="DiaryEditor">
        <h2>오늘의 일기</h2>
        <div>
          <input
            name="author"
            value={state.author}
            onChange={(e) => {
              //값이 바뀌었을때 사용하는 이벤트
              setState({
                ...state,
                //author:state.author, content:state.content 
                //setState()이 실행되도 author의 이벤트만 변경되고 
                //content의 값은 유지가 되는거다.
                author: e.target.value,
                //만약 ...state가 밑으로 오게되면 author은 변경 되었지만 다시 
                //author:state.author이 실행되기 때문에 값은 바뀌지 않는다.
              })
            }}
          />
        </div>
        <div>
          <textarea
            value={state.content}
            onChange={(e) => {
              setState({
                ...state,
                content: e.target.value,
              })
            }}
          />
        </div>
      </div>
    }
    export default DiaryEditor;

    이렇게 되도 동작은 하지만 이벤트핸들러가 방식이 동일한데 두개로 나눠져 있기 때문에

    하나로 합칠 수 있다.

    import { useState } from "react";
    
    const DiaryEditor = () => {
    
      const [state, setState] = useState({
        author: "",
        content: "",
      })
    
      const handleChangeState = (e) => {
        setState({
          ...state,
          //author:state.author
          //content:state.content
          [e.target.name]: e.target.value
          //author:author자리에 입력된 바뀐 값
          //content:content자리에 입력된 바뀐 값
        })
      }
    
      return <div className="DiaryEditor">
        <h2>오늘의 일기</h2>
        <div>
          <input
            name="author"
            value={state.author}
            onChange={handleChangeState}
          />
        </div>
        <div>
          <textarea
            name="content"
            value={state.content}
            onChange={handleChangeState}
          />
        </div>
      </div>
    }
    export default DiaryEditor;

     

    1~5점까지 오늘의 감정점수 넣기

    저장하기 버튼넣기

    import { useState } from "react";
    
    const DiaryEditor = () => {
    
      const [state, setState] = useState({
        author: "",
        content: "",
        emotion: 1,
      })
    
      const handleChangeState = (e) => {
        setState({
          ...state,
          //author:state.author
          //content:state.content
          [e.target.name]: e.target.value
          //author:author자리에 입력된 바뀐 값
          //content:content자리에 입력된 바뀐 값
        })
      }
    
      const handleSubmit = () => {
        console.log(state)
        alert("저장 성공!")
    //저장하기를 눌렀을때 {author: '나는', content: '일기다.', emotion: '3'} 콘솔에 찍히고 
    //"저장 성공!" 이라는 팝업창이 뜬다.
      }
    
      return (
        <div className="DiaryEditor">
          <h2>오늘의 일기</h2>
          <div>
            <input
              name="author"
              value={state.author}
              onChange={handleChangeState}
            />
          </div>
          <div>
            <textarea
              name="content"
              value={state.content}
              onChange={handleChangeState}
            />
          </div>
          <div>오늘의 감정점수 :
            <select name="emotion"
              value={state.emotion}
              onChange={handleChangeState}
            >
              <option value={1}>1</option>
              <option value={2}>2</option>
              <option value={3}>3</option>
              <option value={4}>4</option>
              <option value={5}>5</option>
            </select>
          </div>
          <div>
            <button onClick={handleSubmit}>저장하기</button>
          </div>
        </div>
      )
    }
    export default DiaryEditor;
    .DiaryEditor{
      border: 1px solid gray;
      text-align: center;
      padding: 20px;
    }
    .DiaryEditor input,textarea{
      margin-bottom: 20px;
      width: 500px;
      padding: 10px;
    }
    
    .DiaryEditor textarea{
      height: 150px;
    }
    
    .DiaryEditor select{
      width: 300px;
      padding: 10px;
      margin-bottom: 20px;
    }
    
    .DiaryEditor button{
      width: 500px;
      padding: 10px;
      cursor: pointer;
    }

    css를 넣을때는 모든 태그를 감싸고있는 최상위 태그에 className을 넣어서 그 클래스로 css를 준다.

    결과 값 !

    리엑트 띠용....진짜 띠용....

    ㅠㅠ 너무 어렵고 프레임워크가 정해놨으니까 그대로 따라야하는건 알지만....

    그걸 잘 모르겠다 하핳...자바스크립트를 못쓸거같음.....허허허...

    공부하면할수록 자신감이 없어지고 ......

    아니다 할 수 있 다 리 ...!!아즈아!!!

Designed by Tistory.