React를 공부하면서 공식문서를 보며 생각날때마다 보기위함이고,
또한
아직 완벽하게 알고있는것도 아니고, 공식문서에 있는걸 공부하면서 보기편하게 정리하면서 한번 더 기억하기 위함이다.
react에서 본질적으로 렌더링 로직이 UI로직 (이벤트가 처리되는 방식, 시간에 따라 state가 변하는방식, 화면에 표시하기 위해 데이터가준비되는 방식 등)
React - 별도의 파일에 마크업 / 로직
JSX구문안에서 javascript 구문은 { } 으로 감싸줘야된다 .
render 함수의 return 으로 “JSX 문법을 사용한 것”으로 반환하고 있다.
아래에 사진은 JSX를 사용한 코드와 JSX를 사용하지 않는 코드를 나타내보았다.
참고로 React 엘리먼트는 ‘불변객체’ 라서 생성 이후 해당 엘리먼트의 자식이나 속성을 변경할수 없다.
<div id="root">
</div>
이 안에 들어가는 모든 엘리먼트를 React DOM에서 관리하기 때문에 이것을 “루트(root)” DOM 노드라고 부른다.
React로 구현된 애플리케이션은 일반적으로 하나의 루트 DOM 노드가 있는데, React를 기존 앱에 통합하려는 경우 원하는 만큼 많은 수의 독립된 루트 DOM 노드가 있을 수 있다.
React 엘리먼트를 루트 DOM 노드에 렌더링하려면 둘 다 [ReactDOM.render()]
로 전달하면 된다.
const element = <h1>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
ReactDOM.render(element, container [, callback]);
React 엘리먼트를 container DOM에 렌더링하고 컴포넌트에 대한 참조를 반환함. (무상태의 컴포넌트는 null값을 반환한다.)
React 엘리먼트가 이전에 container 내부에 렌더링 되었다면 해당 엘리먼트는 업데이트하고 최근의 React 엘리먼트를 반영하는데 필요한 DOM만 변경한다.
추가적인 콜백이 제공되면 컴포넌트가 렌더링 되거나 업데이트 된 후 실행됨.
컴포넌트를 정의하는 가장 간단한 방법 = 자바스크립트 함수
function Practice(props) {
return {props, name}
}
: 함수 데이터를 가진 하나의 “props” (* props 란? 속성을 나타내는 데이터)
객체인자를 받은 후 , react 엘리먼트를 반환.
class Practice extends React.Component {
render() {
return 연습해보는 {this.props.name}
}
}
React의 엘리먼트는 사용자 정의 컴포넌트로 나타낼수있다.
const element = <Practice name="리액트의 컴포넌트"/>
React가 내가 정의한 컴포넌트로 작성한 엘리먼트를 발견하면
JSX어트리뷰트와 자식을 해당 컴포넌트에 단일 객체로 전달한다.
이 객체를 “ props “ 라고 한다.
아래의 코드는 위에 작성한 “리액트의 컴포넌트”를 렌더링하는 예시코드이다.
fuction Practice(props) {
return {props, name}
}
const element = <Practice name = "리액트의 컴포넌트" />
ReactDOM.render(
element,
document.getElementById('root')
)
*순수 함수란?
fuciton sum(a, b){
return a + b;
}
❗ 반면 아래의 함수는 자신의 입력값을 변경하기 때문에 순수함수가 아님
fuction withdraw(account, amount){
account.total -= amount;
}
State는 직접수정X
this.setState( { … } ); 처럼 setState함수를 사용해서 수정해야한다.
function Clock(props){
return(
<div>
{props.date.toLocalTimeString()}
</div>
);
}
reactDOM.render(
<Clock/>,
document.getElementById('root')
);
setInterval(tick,1000);
엘리먼트를 생성하고 이것을 ReactDOM.render()로 전달하는것
위 함수는 setInterval() 콜백을 이용해서 초마다 ReactDOM.render()를 호출하고있음 (렌더링 된 출력값을 변경하고있다.)
*하지만 여기서 clock
이 스스로 업데이트하도록 만드려면 아래의 코드를 넣어준다.
function tick(){
root.render(<clock date={new Date()} />);
}
이것을 구현하기 위해서 Clock 컴포넌트에 “state”를 추가해야한다.
여기서 State는 props와 유사하지만, 비공개이며 컴포넌트에 의해 완전히 제어된다.
😀 그렇다면 함수에서 클래스로 변환을 시켜보자.
여기서 5단계를 거쳐 함수의 컴포넌트를 클래스로 변환시킬수 있다.
class Clock extends React.Component{
render(
<div>
현재시간 {this.props.date.toLocaleTimeString()}
</div>
);
}
}
이 클래스로의 변환은 Clock은 클래스로 정의 되어지고,
render 메서드는 업데이트가 발생할 때마다 호출되지만 , 같은 DOM 노드로
을 렌더링하는 경우 Clock 클래스의 단일 인스턴스만 사용됨.
const root = ReactDOM.createRoot(document.getElementById('root'));
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
function tick() {
root.render(<Clock date={new Date()} />);
}
setInterval(tick, 1000);
💡여기서... setState()에 대해 알아야될 3가지 !
this.state.comment= ‘hello’;
대신에 setState()
를 사용한다.
// Correct
this.setState({comment: 'Hello'});
this.state
를 지정할 수 있는 유일한 공간은 바로 constructor이다
state 업데이트는 비동기적일수도 있음
React는 성능을 위해 여러 setState()
호출을 단일 업데이트로 한꺼번에 처리할 수 있다.
this.props
와 this.state
가 비동기적으로 업데이트될 수 있기 때문에 다음 state를 계산할 때 해당 값에 의존해서는 안된다.
State의 업데이트는 병합된다 .
setState()
를 호출할 때 React는 제공한 객체를 현재 state로 병합한다
그리고 이러한 변수를 독립적으로 업데이트할수있음 .
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
병합은 얕게 이루어지기 때문에 this.setState({comments})
는
this.state.posts
에 영향을 주진 않지만 this.state.comments
는 완전히 대체됨
❓왜 리액트생성자(constructor) 메서드안에서 super(props)를 선언하는거지?
💡 자바스크립트 에서는 super
는 부모 클래스 생성자를 가리킨다
(리액트에서는 React.Component
)
중요한것은, super(props) 선언전까지 constructor에서 this
키워드를 사용 할 수 없다.
자바스크립트에서는 허용되지 않는다.
(왜냐하면, this 키워드는 생성자를 가르킬때 사용하기 때문이다.)
대표적인 라이프사이클에는 아래와 같은 것들이 있다.
(출생 - 인생- 사망)
❓ 그렇다면 컴포넌트는 언제 언마운트 될까?
:상위 컴포넌트에서 현재 컴포넌트를 더이상 화면에 표시하지않게 될때. ( 위에 있는 componentWillUnmount가 호출됨)
함수형 컴포넌트에서는 각각의 라이프사이클 메소드를 useEffect 하나로 통일시킬 수 있다.
대신 dependency를 선언 해줘서 시점을 구분한다.
useEffect(() => {
console.log('hi')
}, [/* dependency 선언하는 곳 */])
useEffect 안에 콜백함수를 불러온 뒤 2번째 인자의 배열 안에 업데이트의 기준이 되는 상태를 선언하면 그 상태의 값에 따라 컴포넌트를 업데이트 할 수 있고,
빈 배열을 선언하면 최초 로드 시에만 렌더링이 된다.
💡 useEffect와 useState에 대한 더 많은 설명
Lifecycle 메서드 클래스에 추가하기.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
<Clock />
가 ReactDOM.render()
로 전달 되었을 때
React는 Clock
컴포넌트의 constructor를 호출 한다.
Clock
이 현재 시각을 표시해야 하기 때문에
현재 시각이 포함된 객체로 this.state
를 초기화 한다.
나중에 이 state를 업데이트할 것이다.
React는 Clock
컴포넌트의 render()
메서드를 호출합니다.
이를 통해 React는 화면에 표시되어야 할 내용을 알게 된다.
그 다음 React는 Clock
의 렌더링 출력값을 일치시키기 위해 DOM을 업데이트함.
Clock
출력값이 DOM에 삽입되면,
React는 componentDidMount()
생명주기 메서드를 호출한다.
그 안에서 Clock
컴포넌트는 매초 컴포넌트의 tick()
메서드를 호출하기 위한 타이머를 설정하도록 브라우저에 요청한다.
매초 브라우저가 tick()
메서드를 호출합니다.
그 안에서 Clock
컴포넌트는 setState()
에 현재 시각을 포함하는 객체를 호출하면서 UI 업데이트를 진행합니다.
setState()
호출 덕분에 React는 state가 변경된 것을 인지하고 화면에 표시될 내용을 알아내기 위해 render()
메서드를 다시 호출한다.
이 때, render()
메서드 안의 this.state.date
가 달라지고 렌더링 출력값은 업데이트된 시각을 포함하고, React는 이에 따라 DOM을 업데이트합니다.
Clock
컴포넌트가 DOM으로부터 한 번이라도 삭제된 적이 있다면 React는 타이머를 멈추기 위해 componentWillUnmount()
생명주기 메서드를 호출한다.❓ 캐멀케이스? 그게뭐죠?
그냥 변수명을 부르는이름이다.
예를들어, 이런식으로.
- 스네이크케이스 : React_learn
- 캐멀케이스: reactLearn
HTML
<button onclick="activate">
버튼
</button>
React
<button onClick={active}>
버튼
</button>
false
를 반환해도 기본동작을 방지한다.hooks 을 사용하면 함수 컴포넌트도 클래스컴포넌트의 기능들을 모두 사용할 수 있음 .
state 와 생명주기에 갈고리를 걸어 원하는 시점에 정해진 함수를 실행시키기 위해서(모두 use로 시작함.)
훅은 최상위 레벨(리액트 컴포넌트)에서만 호출해야한다.
따라서 반복문 / 조건문 or 중첩된함수에서 hook을 쓰면안된다.
훅은 컴포넌트가 렌더링 될때마다 매번 같은 순서로 호출되어야 한다.
이런식으로 함수를 전달하는 방식에도 차이가 있다.