[23.09.27] 42일차
<<진도>>
Front-end
- 리액트 React 문법(JSX)
- 리액트 엘리먼트 React element
- 컴포넌트 Component
- 리액트에서의 event
<<오늘의 팁>>
- 확장 ‘Errorlens’
syntax에러나 오류 시 알림보여줌
- HTML 태그 내 js영역 {} 주석 가능형태
const favorites = (
<ul class="favorites">
{
// hi
}
{
/* test('수요일') */
}
{/* 100 + 5 */}
</ul>
);
- React에서는 ‘class’가 다른 기능적 의미를 가지고있기 때문에 태그의 class는
“className”으로 표기해야한다. (but, 렌더링 시엔 ‘class’ 로 나온다)
ex) <div class=“class”> X => <div className=“className”> O
기본
* ex01-javascript // 순수 자바스크립트 형태
<body>
<h1>상품 1페이지</h1>
<form action="">
<input type="text" name="name" placeholder="상품명을 입력하세요">
<button type="submit">추가</button>
</form>
<div class="main-card">
<img src="img/food-one.jpg" alt="올리브 오일" width="400">
<button>❤</button>
</div>
<ul class="favorites">
<li>
<img src="img/food-one.jpg" alt="음식">
</li>
<li>
<img src="img/food-two.jpg" alt="음식">
</li>
<li>
<img src="img/food-three.jpg" alt="음식">
</li>
</ul>
<!-- script -->
<script>
// 1. 하트 버튼 엘리먼트 접근
const heartButton = document.querySelector('.main-card button');
// 2. 하트 버튼 클릭하면, 이미지 추가(li > img)
heartButton.addEventListener('click', () => {
// 3. 하트 색 변경
heartButton.innerText = '💜';
// 4. li 엘리먼트생성
const li = document.createElement('li');
// 5. img 엘리먼트생성
const img = document.createElement('img');
img.src = "img/food-one.jpg"; // img src 접근
console.log('img :', img);
// 6. li 자식으로 img 추가 (li > img)
li.appendChild(img);
console.log('li :', li);
// 7. ul 엘리먼트 접근 : li가 추가될 엘리먼트
const favorites = document.querySelector('ul.favorites')
// 8. ul에 li추가
favorites.appendChild(li);
});
</script>
[리액트 React]
공식홈페이지: https://ko.legacy.reactjs.org/
[리액트 라이브러리 연결] JavaScript에서 사용하기 사전단계
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
작업하는 script위에 넣어줘야한다
<script type = "text/babel">
** Babel : 웹브라우저 js가 처리하지 못하는 형태 언어를 변환하여 처리해주는 역할
const foodItem = (
<li>
<img src="img/food-one.jpg" alt="음식" />
</li>
);
형태를
[JSX]
JS: JavaScript / X: Xml
[react] JSX =================================================
: JavaScript + XML(html같은 마크업 랭귀지)
: JavaScript내에 HTML 작성 가능
: HTML 태그 내 JavaScript 작성하려면, {} 사용
: 작성된 HTML을 '리액트 엘리먼트'라고 한다.
=============================================================
ReactDOM :
const root = ReactDOM.createRoot(domContainer);
root.render(e(LikeButton));
웹브라우저가 렌더할때의 DOM이 아닌 react실행시 복사된 가상DOM
* ex02-react-JSX
<body>
<div id="food-li-insert"></div>
<!-- React를 실행. -->
<!-- 주의: 사이트를 배포할 때는 "development.js"를 "production.min.js"로 대체하세요. -->
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel"> // babel : js에서 html태그를 인식하게 하기위한
/*
[react] JSX =================================================
: JavaScript + XML(html같은 마크업)
: JavaScript내에 HTML 작성 가능
: HTML 태그 내 JavaScript 작성하려면, {} 사용
: 작성된 HTML을 '리액트 엘리먼트'라고 한다.
=============================================================
*/
console.log('처음 배우는 리액트');
const foodItem = (
<li>
<img src="img/food-one.jpg" alt="음식" />
</li>
);
// [React문법] JSX에서는 닫는 태그 표시가 필수 닫는 태그가없다면 끝나는 의미로 '/'가 들어간다.
const hi = '오늘도 좋은 하루';
function test(args) {
return `인수는 ${args}입니다.`;
}
const title = (
<h1>상품 1페이지</h1>
);
const mainCard = (
<div class="main-card">
<img src="img/food-one.jpg" alt="올리브 오일" width="400" />
<button>❤</button>
</div>
);
const form = (
<form action="">
<input type="text" name="name" placeholder="상품명을 입력하세요" />
<button type="submit">추가</button>
</form>
);
const favorites = (
<ul class="favorites">
{foodItem}
{foodItem}
{foodItem}
</ul>
);
// 다수 리액트 엘리먼트를 렌더링 할 때 app으로 묶어서 렌더
const app = (
// 다수의 element를 처리하기 위해서는 묶어주는 부모요소가 필요
<div>
{title}
{mainCard}
{form}
{favorites}
</div>
);
// 리액트 엘리먼트가 추가될 위치
const foodListInsert = document.querySelector('#food-li-insert');
// 리액트를 이용하여 엘리먼트 추가
// [ver.17까지의 형태]
// ReactDOM.render(리액트엘리먼트, 엘리먼트);
// ReactDOM.render(foodItem, foodListInsert);
// [ver.18]
// ReactDOM.createRoot(엘리먼트).render(리액트엘리먼트);
// ReactDOM.createRoot(foodListInsert).render(foodItem);
ReactDOM.createRoot(foodListInsert).render(app);
// .render()메서드는 하나만 가능
// 각각 변수에 저장된 엘리먼트들의 렌더링을 한번에 하고싶을 때는 묶어서 렌더
</script>
* ex02-react-JSX-clean
[JavaScript에 html 태그를 넣어 렌더하는 JSX문법]
<body>
<div id="food-li-insert"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
const title = <h1>상품 1페이지</h1>;
const form = (
<form action="">
<input type="text" name="name" placeholder="상품명을 입력하세요" />
<button type="submit">추가</button>
</form>
);
const mainCard = (
<div class="main-card">
<img src="img/food-one.jpg" alt="올리브 오일" width="400" />
<button>❤</button>
</div>
);
const foodItem = (
<li>
<img src="img/food-one.jpg" alt="음식" />
</li>
);
const favorites = (
<ul class="favorites">
{foodItem}
{foodItem}
{foodItem}
</ul>
);
// 여러 리액트 엘리먼트를 렌더링하고자 할 때 묶어주기
const app = (
<div>
{title}
{form}
{mainCard}
{favorites}
</div>
);
// 리액트 엘리먼트가 추가될 위치
const foodListInsert = document.querySelector('#food-li-insert');
// 리액트를 이용하여 엘리먼트 추가
ReactDOM.createRoot(foodListInsert).render(app);
</script>
* ex03-react-component-ex
컴포넌트 연습
<div id="text"></div>
<hr>
<script type="text/babel">
// 1. 리액트 엘리먼트를 변수에 저장 --------------------------------
const h1 = <h1>안녕하세요</h1>;
const one = 100;
const ul = (
// [react element] ==========================
// {one} // html 영역이 아닌곳에서 {}는Error
// console.log(); //리액트 element가 오는데 js 문법도 Error
<ul>
<li>첫 번째</li>
<li>두 번째</li>
</ul>
);
const app = (
<div>
{h1}
{ul}
</div>
);
// 2. 컴포넌트 생성 ------------------------------------------------
/*
[문법] ======================================================
// 컴포넌트를 생성하는것은 함수 정의와 같음.
// but, 이름은 대문자로 시작!
function 대문자시작(props) { // props = properties(속성들)
// 명령어;
// 어떤 코드가 오든 마지막엔 React element
return (리액트 엘리먼트);
}
=============================================================
*/
const userName = '홍길동';
function H1({ name, age }) { // 대문자 시작 중요(강제)
// console.log('props : ', props);
console.log(name, age);
// props는 Object 객체 형태
return (
<div>
<h1>안녕하세요, {name}님!</h1>
<div>나이는 {age}세 입니다.</div>
</div>
);
}
// 익명 함수 / 화살표 함수 형태도 컴넌트명은 무조건 대문자로 시작
const Ul = () => {
return (
<ul>
<li>첫 번째</li>
<li>두 번째</li>
</ul>
);
};
const componentApp = (
// 컴포넌트는 리액트 엘리먼트 태그형태로 쓴다.
// 하나만 들어가도 부모필요
<div>
<H1 name="박보검" age="25" />
<H1 name={userName} age="35"></H1>
{H1({ name: '이미자', age: 52 })}
<Ul />
</div>
);
const ComponentApp = () => {
console.log('== [ 컴포넌트 앱 ] ==');
return (
<div>
<H1 name="박보검" age="25" />
<H1 name={userName} age="35"></H1>
{H1({ name: '이미자', age: 52 })}
<Ul />
</div>
);
}
const insert = document.getElementById('text');
// ReactDOM.createRoot(insert).render(app);
// ReactDOM.createRoot(insert).render(componentApp);
ReactDOM.createRoot(insert).render(<ComponentApp />);
</script>
* ex03-react-component
<div id="food-li-insert"></div>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel">
// /react element/
// const title = <h1>상품 1페이지</h1>;
// * component (이름있는 함수 선언식 정의)
function Title(props) {
// return <h1>상품 1페이지</h1>;
return <h1>{props.children}</h1>;
{/* content(페이지1)는 상위 props의 자식(children)으로 받아준다 */ }
}
// /react element/
// const form = (
// <form action="">
// <input type="text" name="name" placeholder="상품명을 입력하세요" />
// <button type="submit">추가</button>
// </form>
// );
// * component (익명함수)
const Form = function () {
return (
<form action="">
<input type="text" name="name" placeholder="상품명을 입력하세요" />
<button type="submit">추가</button>
</form>
);
}
// /react element/
// const mainCard = (
// <div class="main-card">
// <img src="img/food-one.jpg" alt="올리브 오일" width="400" />
// <button>❤</button>
// </div>
// );
// * component (화살표 함수)
const MainCard = ({ src }) => {
function heartClick() {
console.log('하트버튼 클릭!!!');
}
return (
<div class="main-card">
<img
src={src}
alt="올리브 오일"
width="400"
// CSS 추가
style={{ border: "1px solid #f00", }}
// 외부{}=<태그>내에서 css/js표현식
// 내부{}=객체표시
/>
<button onClick={heartClick}>❤</button>
</div>
);
}
// /react element/
// const foodItem = (
// <li>
// <img src="img/food-one.jpg" alt="음식" />
// </li>
// );
// * component
const FoodItem = ({ src }) => {
// console.log('FoodItem props', props);
return (
<li>
<img src={src} alt="음식" />
</li>
);
};
// react element
// const favorites = (
// <ul class="favorites">
// {foodItem}
// {foodItegm}
// {foodItem}
// </ul>
// );
// * component
const Favorites = () => {
return (
<ul class="favorites">
<FoodItem src="img/food-one.jpg" />
<FoodItem src="img/food-two.jpg" />
<FoodItem src="img/food-three.jpg" />
</ul>
);
};
// 여러 리액트 엘리먼트를 렌더링하고자 할 때 묶어주기
const app = (
<div>
{/* title */}
<Title>페이지 1</Title>
{/* content(페이지1)는 상위 props의 자식(children)으로 받아준다 */}
{/* form */}
<Form />
{/* mainCard */}
<MainCard src="img/food-one.jpg" />
{/* foodItem */}
<Favorites />
</div>
);
// 리액트 엘리먼트가 추가될 위치
const foodListInsert = document.querySelector('#food-li-insert');
// 리액트를 이용하여 엘리먼트 추가
ReactDOM.createRoot(foodListInsert).render(app);
</script>
* ex03-react-component-clean
<script type="text/babel">
// * component
function Title(props) {
return <h1>{props.children}</h1>;
}
// * component
const Form = function () {
return (
<form action="">
<input type="text" name="name" placeholder="상품명을 입력하세요" />
<button type="submit">추가</button>
</form>
);
}
// * component
const MainCard = ({ src }) => {
function heartClick() {
console.log('하트버튼 클릭!!!');
}
return (
<div class="main-card">
<img
src={src}
alt="올리브 오일"
width="400"
// CSS 추가
style={{ border: "1px solid #f00", }}
/>
<button onClick={heartClick}>❤</button>
</div>
);
}
// * component
const FoodItem = ({ src }) => {
return (
<li>
<img src={src} alt="음식" />
</li>
);
};
// * component
const Favorites = () => {
return (
<ul class="favorites">
<FoodItem src="img/food-one.jpg" />
<FoodItem src="img/food-two.jpg" />
<FoodItem src="img/food-three.jpg" />
</ul>
);
};
// 여러 리액트 엘리먼트를 렌더링하고자 할 때 묶어주기
const app = (
<div>
<Title>페이지 1</Title>
{/* content(페이지1)는 상위 props의 자식(children)으로 받아준다 */}
<Form />
<MainCard src="img/food-one.jpg" />
<Favorites />
</div>
);
// 리액트 엘리먼트가 추가될 위치
const foodListInsert = document.querySelector('#food-li-insert');
// 리액트를 이용하여 엘리먼트 추가
ReactDOM.createRoot(foodListInsert).render(app);
</script>
* ex04-react-event
<script type="text/babel">
// * component
function Title(props) {
return <h1>{props.children}</h1>;
}
// * component
const Form = () => { // 화살표함수로 component만들면 {}, return 생략가능
// handler + Form + Submit
function handlerFormSubmit(event) {
console.log('추가버튼 클릭함!!');
// refresh 방지
event.preventDefault();
}
return (
<form action="" onSubmit={handlerFormSubmit}>
<input type="text" name="name" placeholder="상품명을 입력하세요" />
<button type="submit">추가</button>
</form>
);
};
// * component
const MainCard = ({ src }) => {
function heartClick() {
console.log('하트버튼 클릭!!!');
}
return (
<div className="main-card">
<img
src={src}
alt="올리브 오일"
width="400"
// CSS 추가
style={{ border: "1px solid #f00", }}
/>
<button onClick={heartClick}>❤</button>
</div>
);
}
// * component
const FoodItem = ({ src }) => {
return (
<li>
<img
src={src}
alt="음식"
// css 추가
style={{
width: "150px",
height: "100px",
backgroundSize: "contain",
}}
/>
</li>
);
};
// * component
const Favorites = () => {
return (
<ul className="favorites">
<FoodItem src="img/food-one.jpg" />
<FoodItem src="img/food-two.jpg" />
<FoodItem src="img/food-three.jpg" />
</ul>
);
};
// 여러 리액트 엘리먼트를 렌더링하고자 할 때 묶어주기
const app = (
<div>
<Title>페이지 1</Title>
{/* content(페이지1)는 상위 props의 자식(children)으로 받아준다 */}
<Form />
<MainCard src="img/food-one.jpg" />
<Favorites />
</div>
);
// 리액트 엘리먼트가 추가될 위치
const foodListInsert = document.querySelector('#food-li-insert');
// 리액트를 이용하여 엘리먼트 추가
ReactDOM.createRoot(foodListInsert).render(app);
</script>