개인공부

개발공부 34일차 [유데미 리엑트 강의]

stella0905 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를 준다.

결과 값 !

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

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

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

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

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