✍️ 리액트 기초 문법 & 블로그 제작 실습(강의)을 통해서 작성해본 코드들과 복습+기억해두고 싶은 내용들을 메모해 보았다.
return(
<div className='App'>
<div className='blue-nav'>
<h4 style= {{color: 'blue', fontSize: '16px'}}
>블로그</h4>
</div>
</div>
);
📌 state는 어디에 만들까?
state를 사용하는 컴포넌트 중 최상위 컴포넌트에 만들기
state = state+1
) → html 반영 되지 않는다.state변경함수(새로운state)
와 같이 작성한다.기존 state == 신규state 의 경우 변경 X → 에너지 절약
: reference data type
( 이 부분은 얕은복사의 이론을 알고 있어야 응용가능하다. 🤔 ) 얕은복사와 깊은복사
❗️ arr, obj 복사할 때 주의
: 변수 & 변수 2 화살표(참조)가 같으면 변수1 == 변수2
비교시 true 이며, 결국 업데이트 되지 않는다.
따라서 아래처럼 해줘야 독립적인 array 생성, 즉 리액트가 렌더링을 다시 해줄 수 있다.
→ let copy = [...copy할 것]
: ‘화살표를 다르게 지정' 과 동시에 + 스프레드 문법특징( ...
괄호를 펼친다.) + []
괄호로 다시 씌워준다.) 의 의미이다. 😀
즉, state가 array 나 object 면, 독립적 카피본을 만들어서 수정해 주자. (문자나 숫자 데이터는 괜찮다고 한다.)
onClick={}
안에는 함수이름을 넣어야 한다. console.log(’hi’)
이런식으로 JS 바로 쓸 수 없다.function(){console.log(’hi’)}
onClick={()⇒{ ... }}
1. html + css 로 미리 디자인 완성한다.
2. UI의 현재 상태를 state로 저장한다.
3. state에 따라 UI가 어떻게 보일지 작성한다.
4. 스위치를 작동한다. (필요시 상태변경하기. onClick 등)
디자인 만들기
function App(){
return(
<Modal />
)
}
function Modal() {
return (
<div className='modal'>
<h4>제목</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
);
}
UI 상태 저장하기
let [modal, setModal] = useState(false); // 스위치 역할
state에 따라 UI가 어떻게 보일지 작성한다.
{}
를 사용, js문법을 이용한다.if
문을 JSX에서는 사용할 수 없다.조건식 ? 참일 때 실행할 코드 : 거짓일 때 실행할 코드
{modal === true ? <Modal /> : null}
‘’
텅 빈값 혹은 null
(비어있는 html용으로 자주 사용) 을 입력해 줄 수 있다.스위치를 작동시킨다. (필요시 상태를 변경한다)
<button
onClick={() => {
modal === false ? setModal(true) : setModal(false); // 내가 짠 코드
setModal(!modal); // 솔루션(훨씬 편함)
}}
>
모든 arr
자료 뒤에는 map()
을 사용할 수 있다. 콜백함수를 넣어준다.
JSX 내부 JS식 코드{}
중괄호 안에서는 if처럼 for
도 사용할 수가 없다.
( 굳이 for을 쓴다면 JSX안이 아닌 바깥에서 사용할 수도 있다. )
비슷한 html 반복생성 하려면 map()
을 사용하면 된다! 😀
- array 자료 개수만큼 함수내부 코드를 실행 해준다.
- 함수의 파라미터는 array안에 있던 하나하나의 데이터이다.
- return의 로직을 array로 담아준다.
+) 유용한 파라미터 2개를 사용한다. (두 번째는 정수 인덱스0,1,2...
이다.)
→ map으로 돌린 리스트들 각각의 state를 setState 함수를 통해서 개별 업데이트 시켜주는 것
let [like, setLike] = useState([0, 0, 0]); // 1)
{/* ------------ 리스트 ------------*/}
{title.map((title, i) => (
<div className='list' key={i}>
<h4>
{title}
<span
onClick={() => {
let copyLike = [...like]; // 2)
copyLike[i] = copyLike[i] + 1; //3)
setLike(copyLike); // 4)
}}
>
👍
</span>
{like[i]}
</h4>
<p>2월 17일 발행</p>
</div>
))}
1) [like1, setLike1][like2, setLike2]... 이렇게 각각 하는 것은 비효율적이므로 배열에 상태를 다 담는다.
2) 따라서 객체나 배열데이터의 상태는 ...
스프레드 연산자로 카피본을 만들어주는 것 잊지말기!
3) 필요한 작업을 하기 → 이 부분에서 막혔다. 😵
: onClick에서 setState를 작성하는 순간자체를 맵을 생성하는 단계인 것처럼, 마치 for문을 돌리는 단계처럼 생각해버렸다.
이미 map은 개별적으로 list 들을 다 돌려서 하나하나하나 만들어진 상태이다. 이상태에서 내가 onClick 을 발생 시킨 것은 이미 정해져있는 index의 해당 list 일뿐. 따라서 onClick 내부의 함수는 내가 누른 index와 일치된 상태일 것이다. (이렇게 이해를 했다.) 더 코드를 접해보자. 🤔
4) 간단하게 3)에서 수정된 부분으로 업데이트 해주면 된다.
< 자식컴포넌트 작명 = { state 이름 } >
props.작명
사용 <Modal text=”0” />
✍️ 과제1) 자식 컴포넌트에서 부모컴포넌트의 state 변경하기
1)
// App
{modal === true ? <Modal title={title} setTitle={setTitle} /> : null}
// Modal
function Modal(props) {
return (
<div className='modal'>
<h4>{props.title[0]}</h4>
<p>날짜</p>
<p>상세내용</p>
<button
onClick={() => {
const titleCopy = [...props.title];
titleCopy[0] = '여자코트추천';
props.setTitle(titleCopy);
}}
>
글 수정
</button>
</div>
);
}
2)
function App() {
let [title, setTitle] = useState(['여행지 맛집', '유럽여행', '여행 경비']);
const changeState = (newTitle) => {
const copyTitle = [...title];
copyTitle[0] = newTitle;
setTitle(copyTitle);
};
return()
...
{modal === true ? (
<Modal title={title} setTitle={setTitle} changeState={changeState} />
) : null}
...
}
function Modal(props) {
return (
<div className='modal'>
<h4>{props.title[0]}</h4>
<p>날짜</p>
<p>상세내용</p>
<button
onClick={() => {
props.changeState('여자코트추천');
}}
>
글 수정
</button>
</div>
);
}
solution
<button
onClick={() => {
props.setTitle(['여행지 포토스팟', '유럽여행', '여행 경비']);
}}
>
글 수정
</button>
✍️ 과제2) 내가 놓친 포인트
📌 동적인 UI 만드는 step
을 따르자.let [modalTitle, setModalTitle] = useState(0);
→ 상태는 총 세개. 즉 1 2 3 세개의 상태가 필요할 것이며 초기 상태로 0을 두자. 필요시 1, 2 그리고 다시 0 으로 바뀔 수 있도록 set 설정을 하면 될 듯한 느낌을 갖자.모달 함수로 와서 해당 UI가 동작할 부분을 위와 연관 지어서 유심히 살펴보자
// 이렇게 구현되면 좋겠다 라는 생각을 가진 상태로
<h4>{props.title[0]}</h4> // 첫 번째 제목의 타이틀
<h4>{props.title[1]}</h4> // 두 번째 제목의 타이틀
<h4>{props.title[2]}</h4> // 세 번째 제목의 타이틀
// 이렇게 응용할 수 있어야한다 !!!
// 여기서 modalTitle은 위에서 상태를 설정했던 숫자 0,1,2를 나타낼 수 있음을 !!
<h4>{props.title[props.modalTitle]}</h4>
그럼 이제 실제 요소에 onClick을 동작시켰을 때, setState 함수를 이용해서 원하는 값을 동적으로 갖도록 상태를 변경하는 것에 대해 고민하자. ( 이 부분은 바로 해결했다.😀 )
// App 컴포넌트에서 onClick을 발생시킬때 스테이트 변경을 동적으로 잘 처리하고
<h4
onClick={() => {
setModal(!modal);
setModalTitle(i); // i로 설정한다.
}}
>
// 모달 컴포넌트에서는 바뀐 state를 고대로 props으로 받아와서 적용한다.
<h4>{props.title[props.modalTitle]}</h4>
<input type='text' />
<input type='checkbox' />
<input type='range' />
<select></select>
<textarea />
<input>
에 입력시 코드를 실행하고 싶으면 onChange
/ onInput
을 사용한다.<input onChange={()=>{???}} />
: 유저가 인풋안에 값을 타이핑 할 때마다 안의 코드가 실행된다.onClick = {}
, onChange = {}
, onInput = {}
등 매우 많다.onMouseOver = {}
: 마우스를 가져다 대면 안의 코드 실행onScroll = {}
: 해당 태그에 스크롤바가 있다면 스크롤바를 조작할 때마다 안의 코드 실행 등 필요할 때 잘 찾아서 쓰자✍️let [value, setValue] = useState('');
...
<input
onChange={(e) => {
setValue(e.target.value); // 비동기처리
console.log(value); // 처음 출력시 빈 문자열
}}
/>
이렇게 가져온 값은 보통 변수/state에 저장해서 사용하는 경우가 많다.
e.stopPropagation();
: 상위 html로 퍼지는 이벤트버블링을 막고 싶을 때 사용한다.
state 변경함수는 늦게 처리된다(비동기처리)
: 따라서 먼저 출력하는 것은 console.log 이므로 처음에는 ‘ ’ 빈 문자열이 출력된다.
✍️ 과제3) 게시글 추가 & 삭제 구현하기
<input
onChange={(e) => {
setValue(e.target.value);
}}
/>
<button
onClick={() => {
let titleCopy = [...title];
titleCopy.unshift(value);
setTitle(titleCopy);
// 아래는 추가로 구현한 부분이다.
let likeCopy = [...like];
likeCopy.push(0);
setLike(likeCopy);
}}
>
게시글 추가
</button>
✍️ 내가 삭제를 못 푼 이유..
map()
함수를 처음에 만들 때 받아오는 아이템과 인덱스 그리고 배열 부분
let [title, setTitle] = useState(['여행지 맛집', '유럽여행', '여행 경비']);
{title.map((title, i) => ( // title 을 넣었기 때문
<div className='list' key={i}>
인자의 아이템을 받아오는 첫번째 파라미터 자리에 state와 같은 변수명을 사용했다.
따라서 map() 함수 내부에서 title을 출력했더니 ['여행지 맛집', '유럽여행', '여행 경비'] 의 정상적인 state 배열이 출력되질 않았다.. 이문제를 여기까지 와서 깨달은 이유는 바로
겉보기에는 멀쩡했기 때문이다. 위의 제목도 map()함수로 넘어온 첫번째 요소 즉, 아이템 {title} 을 사용했으니 똑바로 적용 되었고, 콘솔로 title을 출력하면 원래라면 state 배열이 나와야 하겠지만 말그대로 map() 함수의 아이템이 출력되었기 때문에 의심을 하지 않았다. ⚡️
하지만 이상태로 onClick
이벤트 내에서 state 복사본을 만든다면..?
onClick = {()⇒{ let copy = [...title]}}
← 바로 여기서 ...title
문법이 에러가 날 수 밖에없다! 위의 콘솔을 보면 알겠지만 map()의 아이템 즉, 각 문자열이 출력되는데 배열형태가 아니니 배열 복사본을 만드는 것 자체가 말이 안되었던 상황이었다. 😵
따라서 이렇게 계속 코드를 짜게되면 이벤트 동작시 아래와 같은 화면을 만나게 된다.
_
등으로 사용했으면 해결될 문제였다. (그부분을 실제로 사용하지 않고서도 코드를 짜는게 가능했다.)→ 결론적으로 map()
함수의 첫번째 파라미터 요소의 아이템을 useState
의 title과 동일한 이름으로 지어서 생긴 문제였다. title state의 배열을 가져와야 그 배열을 복사하고, 수정하고, setState를 적용할 수 있었는데 나는 계속 문자열 상태였기 때문에 솔루션 로직을 알고 있었더라도, 실행할 수가 없었던 상황 :) 그래도 다음 부터는 실수를 안하겠지! ✍️
📌 아래와 같이 작성하면 된다.
<button
onClick={(e) => {
e.stopPropagation();
let copyTitle = [...title];
copyTitle.splice(i, 1);
setTitle(copyTitle);
}}
>
❌
</button>
reference)
codingapple