참고 사이트:
https://legacy.reactjs.org/docs/handling-events.html
import './App.css';
import Avartar from './components/Avartar';
import Profile from './components/Profile';
function AppProfile() {
return (
<>
<button onClick={(event) => {
console.log(event);
alert("버튼이 클릭됨")
}}>버튼</button>
<Avartar image='https://images.unsplash.com/photo-1574158622682-e40e69881006?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=580&q=80' isNew={true}/>
<Profile
image='https://images.unsplash.com/photo-1574158622682-e40e69881006?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=580&q=80'
name='Hana'
title='프론트엔드 개발자'
isNew={true}
/>
<Profile
image='https://images.unsplash.com/photo-1583512603805-3cc6b41f3edb?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=880&q=80'
name='Anna'
title='백엔드 개발자'
/>
<Profile
image='https://plus.unsplash.com/premium_photo-1661903055250-d4cd3d70f805?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=880&q=80'
name='Bob'
title='백엔드 개발자'
/>
</>
);
}
export default AppProfile;
import './App.css';
import Avartar from './components/Avartar';
import Profile from './components/Profile';
function AppProfile() {
const handleClick = (event) => {
console.log(event);
alert("버튼이 클릭됨");
};
return (
<>
<button onClick={handleClick}>버튼</button>
<Avartar image='https://images.unsplash.com/photo-1574158622682-e40e69881006?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=580&q=80' isNew={true}/>
<Profile
image='https://images.unsplash.com/photo-1574158622682-e40e69881006?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=580&q=80'
name='Hana'
title='프론트엔드 개발자'
isNew={true}
/>
<Profile
image='https://images.unsplash.com/photo-1583512603805-3cc6b41f3edb?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=880&q=80'
name='Anna'
title='백엔드 개발자'
/>
<Profile
image='https://plus.unsplash.com/premium_photo-1661903055250-d4cd3d70f805?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=880&q=80'
name='Bob'
title='백엔드 개발자'
/>
</>
);
}
export default AppProfile;
함수를 따로 정의해서 사용할 수도 있다.
이때 소괄호는 쓰면 안 됨. handleClick() Xx
이러면 핸들클릭 함수가 호출되어 실행된 후에 리턴되는 값이 넘어오는 것
변경 가능 한 데이터를 리액트 라이브러리에게 알려줘야함
const [number, setNumber] = useState(0)
유즈스테이트 안에는 초기값
ㄴ 배열이 리턴됨 선택값을 접근할수 있는 변수와 업데이트 할 수 있는 함수 2개가 리턴됨 통상적으로 함수에 set을 붙임
import React, { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div className='counter'>
<span className='number'>{count}</span>
<button className='button' onClick={()=>{
setCount(count + 1);
}}>Add +</button>
</div>
);
}
근데 왜 자동으로 import 안 되냐…
ㄴ 바로바로~ 왜냐하면 끝까지 useState를 치면 텍스트로 인식하기 때문이다. 치던 중에 자동완성으로 뜨는 useState를 선택해야 자동으로 import 된다.
만약 클릭이 발생했을 때 setCount를 5번 호출하면 어덯게 될까 → 1 ?? 왜지?
왜냐하면,
import React, { useState } from 'react'; export default function Counter() { const [count, setCount] = useState(0) return ( <div className='counter'> <span className='number'>{count}</span> <button className='button' onClick={()=>{ setCount(count + 1); setCount(count + 1); setCount(count + 1); setCount(count + 1); setCount(count + 1); }}>Add +</button> </div> ); }
onClick이 실행될 때 스냅샷이 되어 count값이 저장이 된다. 그래서 지금 초기에는 count = 0이라고 저장이 되고, 이 환경이 리콜백함수에 저장된다.
setCount는 계속 0 + 1을 하는 것이다.
그래서 아무리 많이 호출해도 count가 0으로 고정되어있으니까 1만 플러스 된다.
setCount((prev) => prev + 1);
: 이전 값에 1을 더한걸 리턴한다.
스냅샷 되는데 외부에서 참조하고 있는게 없음! 이전 상태값을 콜백 값으로 전달 받는데 prev에 처음에는 0이 전달 됨
import React, { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0)
return (
<div className='counter'>
<span className='number'>{count}</span>
<button className='button' onClick={()=>{
// setCount(count + 1);
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
}}>Add +</button>
</div>
);
}
이렇게 하면 3이 추가 됨!
비동기적으로 예상치 못한 값을 적을 땐 setCount((prev) => prev + 1); 를 사용하는 것이 안전하다.
직접 해보다 해결되지 않아서 코드 참고로 넘어감
import React, { useState } from 'react';
export default function Counter({total, onClick}) {
const [count, setCount] = useState(0);
return (
<div className='counter'>
<div>
<p className='number'>{count} <span className='total'>/{total}</span></p>
</div>
<button
className='button'
onClick={()=>{
setCount((prev) => prev + 1);
onClick();
}}
>Add +</button>
</div>
);
}
그냥 handleClick으로 함수 자체를 넘겨준건데 왜 외부의 값이 변하는 거지?
ㄴ 함수 안에서 외부의 값을 건드리고 있음!
.total {
font-size: 1rem;
margin-left: -1.5rem;
}
컴포넌트로 만들어나갈 때 공통적으로 필요한 데이터는 부모에 놓고 클릭했을 때 부모에서 해결이 되길 원한다면 props로 전달해주면 된다
ㄴ 함수의 주소를 전달해주는 건가봐 그 기능을 주는게 아니라
강의 댓글 중 :
setState를 그대로 전달하는 건 외부에 데이터 변경의 주도권을 넘겨주는 것과 같으니, 콜백함수로 감싸서 넘기고 자식 컴포넌트가 그것을 적절한 시점에 호출만 하도록 해야하는 군요! 그럼 호출하는 입장은 그 기능의 세부 로직은 알지 못하니까요!
깃 사용방법 정리 참고사이트 :
https://wordbe.tistory.com/entry/Git-사용-방법-정리commit-push-pull-request-merge-등
json을 동적으로 가져와서 사용함
비동기, fetch 사용하면 바로 경로 파일에 접근할 수 있음
import React, { useState } from 'react';
export default function Products() {
const [count, setCount] = useState(0);
const [products, setProducts] = useState([]);
fetch('data/products.json') // 비동기
.then(res => res.json()) // json 형태로 변환 (배열)
.then(data => {
console.log('뜨근 데이터 네트워크에서 받아옴');
setProducts(data);
})
return (
<>
<ul>
{products.map((product) => (
<li key={product.id}>
<article>
<h3>{product.name}</h3>
<p>{product.price}</p>
</article>
</li>
))}
</ul>
<button onClick={() => setCount((prev) => prev + 1)}>{count}</button>
</>
);
}
해당 방법은 계속해서 fetch하고 매우 비효율 적임 : 무한 루프에 빠짐
첫번째만 데이터를 받아오고 다시는 받아오지 않게해야함 이걸 사용하는 것이 useEffect
두번째 인자로 텅빈 배열을 전달해줘야함
화면에서 컴포넌트가 사라질때 리턴되는 함수
import React, { useEffect, useState } from 'react';
export default function Products() {
const [count, setCount] = useState(0);
const [products, setProducts] = useState([]);
useEffect(() => {
fetch('data/products.json') // 비동기
.then(res => res.json()) // json 형태로 변환 (배열)
.then(data => {
console.log('뜨근한 데이터를 네트워크에서 받아옴');
setProducts(data);
});
return () => {
console.log('깨끗하게 청소하는 일들을 합니다.')
}
}, []);
return (
<>
<ul>
{products.map((product) => (
<li key={product.id}>
<article>
<h3>{product.name}</h3>
<p>{product.price}</p>
</article>
</li>
))}
</ul>
<button onClick={() => setCount((prev) => prev + 1)}>{count}</button>
</>
);
}
import React, { useState } from 'react';
import './App.css';
import Products from './components/Products';
export default function AppProducts() {
const [showProducts, setShowProducts] = useState(true);
return (
<div>
{showProducts && <Products />}
<button onClick={() => setShowProducts((show) => !show)}>Toggle</button>
</div>
);
}
다시 요청이 필요할 때가 있음
저 checked 배열이 checked가 변경이 될 떄마다 어쩌구래
처음으로 무거운 일을 처리해야할때 useEffect을 유용하게 사용함
리스트안에 사용되는 자식들은 key라는 값을 전달해줘야하고 고유한 인덱스 값을 가지고 있어야함
이렇게 키값을 부여해주면 뜨지 않음
좋은 글이네요. 공유해주셔서 감사합니다.