개발공부 34일차 [유데미 리엑트 강의]
JSX (리엑트에서 주로 사용하는 표현식)
리엑트는 자바스크립트 기반으로 동작한다.
컴퍼넌트 만들기
- 헤더역할을 할 컴퍼넌트 먼저 만든다.
src디렉토리 아래에 파일을 하나 생성한다. MyHeader.js - 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;
- { useState }를 사용하기 위해 import한다.
- 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를 준다.
결과 값 !
리엑트 띠용....진짜 띠용....
ㅠㅠ 너무 어렵고 프레임워크가 정해놨으니까 그대로 따라야하는건 알지만....
그걸 잘 모르겠다 하핳...자바스크립트를 못쓸거같음.....허허허...
공부하면할수록 자신감이 없어지고 ......
아니다 할 수 있 다 리 ...!!아즈아!!!