2주차에는 JSX 문법과 state/props에 대해 배웠다 !
→ JavaScript를 확장한 문법으로 js 코드 안에서 ui관련 작업을 할 수 있다고 한다! 일반 html 태그를 사용해 가독성이 좋고 js로직 사용이 가능하기 때문에 활용도도 높다 !
그럼 HTML과의 차이는 무엇일까?
⇒ HTML은 마크업을 위한 언어이고 JSX는 JS 코드의 일부이므로
문법이 다르다.
function App() {
return (
<h1>Hello</h1>
<p>Like lion</p>
)
}
<div>
와 같은 태그로 감싸도 되나 의미없는 태그를 사용하지 않는 것이 좋다. <div>
보다 <Fragment>
나 <>
를 사용하면 된다!
ex) className, onClick, onChange → 요런 형태를 camelCase라고 하고 JSX에서는 이렇게 작성해주어야 한다!
function App(){
const name = "Kevin";
const friends = ["David", "Lilly"];
return(
<>
<h1>{name}</h1>
{friends.map((friend, i) => (
<p key={i}>{friend}</p>
))
</>
);
}
위의 코드를 실행하면
David Lilly
👆 이런식으로 웹 브라우저에 표시될 것이다!
⇒ 자바스크립트 표현식을 사용하기 위해서는 { }
안에 넣어서 사용해야 한다.
function App(){
const name = "소연";
return <>
{name === "소연" ? <h1>나는 {name}</h1> : <h1>나는 {name}이 아니야</h1>}
</>
}
클래스 컴포넌트란 리액트에서 제공하는 React.Component 클래스를 상속하는 컴포넌트이다.
UI는 render()함수 내에 JSX 코드를 작성해 표기한다.
class React extends React.Comonent{
render(){
return <h1>Hello, {this.props.name}</h1>;
}
}
클래스 컴포넌트의 경우 클래스의 멤버 변수를 직접적으로 수정하지 않는 한 한 번 만들어지면 계속 그 값이 유지된다.
그래서 render함수가 아무리 많이 호출되도 사용자에게 보여지는 데이터는 일정하다. 부모 컴포넌트에서 전달받는 props
가 변경되는 경우가 있어도 컴포넌트의 자체 this.state
는 변하지 않는다. 따라서 this.state
에 들어 있는 데이터는 변하지 않기 때문에 컴포넌트에서 가지고 있던 데이터를 잃어버리지 않고 사용자에게 일정한 데이터가 보여지는 것이다 !!
**this.state
만 업데이트** 해주면 리액트가 자동으로 render함수를 호출하고 브라우저에 업데이트 해준다!!⇒ 정리
this.state
에 담아두어야 한다.**render
함수에서 JSX문법**을 사용해 데이터를 어떻게 UI로 표기할 지 정의한다.**데이터가 변경 -> UI 업데이트**
리액트에서 컴포넌트를 만들 수 있는 두 번째 방법은 JSX를 리턴하는 함수를 정의하는 것이다!
function React(props){
return <h1>Hello, {props.name}</h1>;
}
Class Component 와의 Function Component의 차이점
⇒ 함수형 컴포넌트는 함수 특성상 함수를 호출할 때마다 함수의 코드 블럭이 다시 실행되고 그 안에 선언된 모든 변수들은 함수가 실행되면서 재정의되고 값이 할당된다. 이처럼 함수가 호출될 때마다 모든 로컬 변수들의 값이 초기화되기 때문에 state를 보관해서 클래스 컴포넌트처럼 일관적으로 사용자에게 보여줄 수 없고 자체적인 데이터(=state)를 가질 수 없다.
원래 state와 life cycle 메서드들은 클래스 컴포넌트에서만 사용할 수 있었지만 React Hook이 도입되면서 함수형 컴포넌트에서도 클래스 컴포넌트의 대부분의 기능들을 사용할 수 있게 되었다!
→ 요즘 트렌드는 함수형 + Hooks
But 클래스형도 알고는 있자!
: 컴포넌트 내부에서 변경 가능한 값, 데이터
Ex1) 영어일 땐 한국어로, 영어가 아닐 땐 다시 영어로 바꾸는 예제
class Message extends Component {
state = {
message: "Hello",
};
handleClick = () => {
const newMessage = this.state.message === "Hello" ? "안녕" : "Hello";
this.setState({ message: newMessage });
};
render() {
return (
<>
<h1>{this.state.message}</h1>
<button onClick={this.handleClick}>언어 바꾸기</button>
</>
);
}
}
Ex2) 카운터
function Counter() {
const [number, setNumber] = useState(0);
const onIncrease = () => {
setNumber(prevNumber => prevNumber + 1);
}
const onDecrease = () => {
setNumber(prevNumber => prevNumber - 1);
}
return (
<div>
<h1>{number}</h1>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
);
}
※ useState 안에 들어가는 값은 해당 state의 초기값이다.
리액트에 업데이트가 필요할 경우에는 setState함수
를 호출해야 한다!!
그 후에 이제 리액트가 UI를 업데이트 하기 위해서 render 함수를 호출하는 것이다.
state를 업데이트할 때 이전 state 값에서 무언가가 계산이 되는 경우라면
→
setState(prevState => newState)
이렇게 화살표 함수를 사용해 이전 state 값을 받아 그걸로 업데이트 되는 값을 만들도록 함수를 호출하는 것이 더 좋다..!!!
- 이유
setState()
는 비동기적으로 작동한다.
→ state를 직접 수정하면서 여러 번 상태를 업데이트 하는 경우 이전 업데이트 내용이 다음 업데이트 내용으로 덮어 쓰여질 수 있고 예상치 못한 버그가 발생할 위험이 있다
- `PureComponent`에서 작동 X
: Properties, 즉 컴포넌트의 속성을 설정할 때 사용하는 요소
부모 컴포넌트에서 자식 컴포넌트에게 요소를 전달하는 것!
: props값이 따로 지정되지 않았을 경우의 default 값을 설정해 주는 것이다.
props와 default 둘 다 설정이 안되면 아무것도 나타나지 않는다.
const Person = ({name, age}) => {
return(
<div>
<h1>Name: {name}</h1>
<h1>Age: {age}</h1>
</div>
);
};
Person.defaultProps = {
name: "소연",
};
위의 코드는 name
은 default가 정해져 있지만 age
는 default가 정해져 있지 않다.
이를 브라우저에서 확인해보면
👆 위처럼 name
은 default값이 나타나지만 age
는 아무것도 나타나지 않을 것이다!
: 컴포넌트 태그 사이의 내용을 보여주는 props
// App.js
const App(){
return(
<Person>요 안에 들어가는 내용이 props의 children</Person>
);
};
// Person.js
const Person = (props) => {
return <h1>{props.children}</h1>;
};
: 타입을 지정해 검증할 때 사용한다.
import PropTypes from 'prop-types'
import PropTypes from "prop-types";
const Person = ({ name, age }) => {
return (
<div>
<h1>Name: {name}</h1>
<h1>Age: {age}</h1>
</div>
);
};
Person.propTypes = {
name: PropTypes.string,
age: PropTypes.number,
};
위의 코드에서 name
의 타입은 string
으로 지정해주고 age
의 타입은 number
로 지정해주었다!