일주일만에 글을 쓰려고하니 벌써 설렌다. 여태 귀찮아서 안 쓴게 절대 아니다.
솔직히 일주일동안 많이 나태해지고 공부를 게을리하기도 했다. 그래서 이번 HA를 많이 걱정 했는데 나름 잘 해결해서 다행이었다. 빨리 다시 정신차리고 공부하는 시간을 늘려 나가야겠다.
리액트를 공부하면서 느낀건 이론을 열심히 공부하고 머리에 익히기보단 실습을 많이 해보는 것이 더 좋다는 생각이 들었다. 그리고 HTML을 자바스크립트로 쓴다는 느낌을 받았다. 고차함수를 활용해 태그를 생성하고 props, state로 내가 원하는 방식으로 컴포넌트 간의 정보를 공유?할 수도 있다.
props is read-only
props는 변하지 않는 값으로 1방향 원칙을 전달 원칙을 지키면서 자식 컴포넌트로 데이터를 넘겨 줄 수 있다.
보통 <div props={data}/>
이런 식으로 props에는 props의 key값을 넣어주고 data에는 value를 넣어준다. 즉, props의 속성은 여러개가 될 수 있고 그렇기 때문에 구조 분해해서 전달 할 수 있다.
props.children은 props를 통해 자식 컴포넌트로 데이터를 전해 줄 때 속성을 따로 주지 않아도 리액트에서 기본적으로 제공하는 키워드이다.
<Tweet >안녕하세요</Tweet>
const Tweet = (props) => {
return (
<div>{props.children}</div> // 안녕하세요
)
}
// App.js
class Twittler extends React.Component { // React에서 제공하는 부모 클래스의 메소드를 사용하고자 한다
constructor(props) {
super(props); // 왜 꼭 써줘야할까?
this.state = {
tweets: [
{
uuid: 1,
writer: "김코딩",
date: "2020-10-10",
content: "안녕 리액트"
},
{
uuid: 2,
writer: "박해커",
date: "2020-10-12",
content: "좋아 코드스테이츠!"
}
]
};
this.addNewTweet = this.addNewTweet.bind(this);
}
render() {
return (
<>
{
this.state.tweets.map(tweet => ( // 여기서 중괄호로 감싸 줄 때 오류가 났었다
// 그래서 retrun을 쓰지 않고 소괄호로 감싸주니 에러가 해결되었다
<SingleTweet key={tweet.uuid} writer={tweet.writer} date={tweet.date}>
{tweet.content}
</SingleTweet>
))
}
</>
)
}
// SingleTweet.js
const SingleTweet = (props) => {
console.log(props) // {tweets: [writer: 작성자, date: 날짜, children: 내용]}
return(
<>
{
<div className="writer">{props.writer}</div>
<div className="date">{props.date}</div>
<div className="children">{props.children}</div>
}
</>
)
}
super(props) 왜 꼭 써줘야할까?
출처: https://bit.ly/3rFZ04Z
super(props)를 선언하기 전엔 class에서 this를 사용할 수 없다고 한다
실제로 콘솔에 찍어보니
class Person {
constructor(name) {
this.name = name;
};
};
class PolitePerson extends Person {
constructor(name) {
this.greetColleagues(); // 이것은 허용되지 않는다. 이유를 읽어보자
super(name);
};
greetColleagues() {
alert('Good morning folks!');
};
};
이런 에러가 떴다
그냥 this를 사용하기 위해선 super를 써야한다는 약속? 이라고 생각해야하나..
아직 이해하기 어렵다..
구조분해의 가장 큰 장점은 JSX에서 중괄화 안에 표현식을 사용 할 때
짧게 써서 보다 직관적으로 어떤 내용이 포함되어 있는지 알 수 있어 코드 가독성이 높아지는 것 같다.
// SingleTweet.js
const Tweets = ({ writer, date, children }) => { // props.children 특성
console.log(writer, date, children) // [작성자, 날짜, 내용]
return(
<>
{
<div className="writer">{writer}</div> // 표현식 안에 어떤 데이터가 들어갔는지
<div className="date">{date}</div> // 코드 작성나가 아닌 다른사람이 봐도
<div className="children">{children}</div> // 한 눈에 알 수 있는 직관성이 있다
}
</>
)
}
내부에서 변하는 값
setState로만 값을 바꿔줘야한다
props는 부모 컴퍼넌트로부터 전달
state는 컴포넌트 내부에서 다뤄진다
input창이나 체크박스 등은 보통 state
컴포넌트 내부에서 state를 관리해주는 메소드
함수나 객체를 이용
이전 상태를 알아야 할 때는 무조건 함수형을 사용한다
setState((preState, props)) => ({
counter: preState + 1
})
상태가 변했을 때 상태가 변경된 곳에서 랜더링이 일어나야 하는데 (랜더링 => 값을 뿌려준다)
setState를 사용하지 않으면 랜더링이 일어나지 않는다(lifecycle)
lifecycle 과정을 반드시 따라가기 위해서 setState를 사용한다
셋스테이트 실행하면 랜더를 하는데 랜더안에 셋스테이트가 있으면
계속 반복
리액트가 똑똑해서 미리 에러가 날 것을 알고 아무것도 하지 않음
Stack overflow 에러!!
undefined에러 방지
class안에서 this는 undefined
원래 window를 가리켜야 하는데
클래스에선 스트릭트 모드로 작동이 돼서 undefined
this는 엄마 찾기
갈 곳이 없기 때문에 window를 찾는다
window는 할머니?
엄마가 명시가 되어있지 않기 때문에 window를 찾는 것
엄마를 명시해주는 가장 쉬운 방법이 bind
컨스트럭터에서 this의 엄마를 명시해주는 것
바인드를 안 해주면 메소드에서 this가 엄마를 찾지 못함
왜? 명시를 안 해주어서 window를 찾아가는데 window는 브라우저에서 사용되는 객체이기 때문
그리고 class는 엄격한 모드를 사용하기 때문
컴포넌트는 자신의 state를 자식 컴포넌트에 props로 전달할 수 있다
생성될 때(화면에 나올 때) constructor -> render -> componentDidMount
업데이트 setState() -> render -> componentDidUpdate
제거될 때(화면에서 사라질 때) componentWillUnmount
만약 API를 통해 서버에서 데이터를 받아오는 함수를 만들 때 componentDidMount를 사용한다
componentDidMount() { // 컴포넌트가 생성될 때 실행되어
this.getServerData() // getServerData 메소드 실행
}
getServerData() {
fetch(url) // fetch를 통해 서버 데이터를 가져온다
.then(res => res.json())
.then(data => {
this.setState({
videos: data.items
})
})
}
컴퍼넌트부터 만듬
바텀업(bottom-up)
하지만 데이터는
탑다운(top-down)
데이터는 위에서 아래로 흐른다
출처: codestate
NewTweetForm: 버튼을 누르는 순간 Tweets에 SingleTweet을 추가해주는 컴포넌트
그럴려면 NewTweetForm도 Tweets의 데이터를 공유해야 함
둘 다 쓰는데 state는 어디다 둬야함????
공통 부모 컴퍼넌트에 넣으면 된다 => Twittler
왜???????????????????????
데이터는 위에서 아래로 흐르기 때문에~
같은 맥락
두 개 이상의 컴퍼넌트가 같은 상태를 사용하고자 할 때 상태 어디에 둬야함?
공통 부모 컴퍼넌트
state를 기반으로 렌더링하는 모든 컴퍼넌트를 찾는다
공통 혹은 더 상위에 있는 컴퍼넌트가 state를 가져야 한다
상태를 수정하는 함수 자체는 Twittler에 있어야 한다
-> 왜냐하면 state가 있는 곳에서 state를 수정 할 수 있다 (state특성)
SingleTweet을 추가하는 함수(addNewTweet) 자체는 Twittler 컴포넌트안에 있는데
함수를 실행하고 싶은 곳은 NewTweetForm이다
어떻게 해주냐
addNewTweet함수 자체를 NewTweetForm에 넘겨준다
addNewTweet(newTweet) {
this.setState((prevState) => {
return { tweets: [...prevState.tweets, newTweet] };
});
}
<NewTweetForm handleChange={this.addNewTweet}/> // (props특성) 상태변경 함수도 밑으로 내려 보낼 수 있다
함수를 내려주고 상태를 올려받는다 => state lifting up