*component란 어떤 JSX를 반환하는 함수라고 생각하면 된다.
<단위 변환기 만들기>
-km <-->miles
-minutes <-->hours
-단위 변환에 필요한 flip 버튼 생성
-옵션 변경 위한 select 생성하기
-새롭게 배운 const [A , B] = React.useState()개념 사용
A: state값
B: state값 재설정하는 modifier
useState에서 modifier함수를 실행하면 해당 component가 새로 rendering됨.
<! DOCTYPE html >
< html >
< body >
< div id =" root " ></ div >
</ body >
< script type = " text/babel " >
//flipped인 상태: hours를 입력받는 상태(!flipped = min을 입력받는 상태)
function MinutesToHours (){
const [ amount , setAmount ]= React . useState (0 );
const [ flipped , setFlipped ] = React . useState (false );
const onChange = ( event ) => {
setAmount (event . target . value );
};
const reset = () => setAmount (0 );
const onFlip = () => {
reset ();
setFlipped (( current ) => ! current );
}
return (
< div >
< div >
< label htmlFor =" minutes " > Minutes</ label >
< input
value = { flipped ? amount * 60 : amount }
id =" minutes "
placeholder = " Minutes "
type = " number "
onChange = { onChange }
disabled = { flipped }
/>
</ div >
< div >
< label htmlFor =" hours " > Hours</ label >
< input
value = { flipped ? amount : Math . round (amount / 60 )}
id =" hours "
placeholder = " Hours "
type = " number "
onChange = { onChange }
disabled ={! flipped }
/>
</ div >
< button onClick ={ reset } > Reset</ button >
< button onClick ={ onFlip } > Flip</ button >
</ div >
);
}
function KmToMiles (){
const [ length , setLength ] = React . useState (0 );
const [ flipped , setFlipped ] = React . useState (false );
const onChange = ( event ) => {
setLength (event . target . value );
};
const reset = () => setLength (0 );
const onFlip =() => {
reset ();
setFlipped (( current ) => ! current );
}
return (
< div >
< div >
< label htmlFor = " Km " > Km</ label >
< input
value = { flipped ? length / 0.621371 : length }
id = " km "
placeHolder = " Km "
type = " number "
onChange = { onChange }
disabled = { flipped }
/>
</ div >
< div >
< label htmlFor = " Miles " > Miles</ label >
< input
value = { flipped ? length : length * 0.621371 }
id = " miles "
placeHolder = " miles "
type = " number "
onChange = { onChange }
disabled = {! flipped }
/>
</ div >
< button onClick ={ reset } > Reset</ button >
< button onClick ={ onFlip } > Flip</ button >
</ div >
)
}
function App (){
const [ index , setIndex ] = React . useState (" xx " );
const onSelect = ( event ) => {
setIndex (event . target . value );
}
return (
< div >
< h1 > Super Converter</ h1 >
< select value = { index } onChange = { onSelect } >
< option value = " xx " > Select your units</ option >
< option value = " 0 " > Minutes & Hours</ option >
< option value = " 1 " > Km & Miles</ option >
</ select >
{ index == " xx " ? " Please select your units " : null }
{ index === " 0 "? < MinutesToHours /> : null }
{ index ===" 1 "? < KmToMiles /> : null }
</ div >
);
}
const root = document . getElementById (" root " );
ReactDOM . render (< App /> , root );
</ script >
</ html >
-----------------------------------------------------------------------------------------------------------------------------------------------------------------*Props: 부모 컴포넌트로부터 자식 컴포넌트에 데이터를 보낼 수 있게 해주는 방법
button 스타일 그대로 적용해서 글자만 바꿔 생성하는 코드
<! DOCTYPE html >
< html >
< body >
< div id =" root " ></ div >
</ body >
< script type = " text/babel " >
//flipped인 상태: hours를 입력받는 상태(!flipped = min을 입력받는 상태)
function Btn ({ text , big }){
console . log (text , big );
return < button style ={{
backgroundColor : " tomato ",
color :" white ",
padding : " 10px 20px ",
border : 0 ,
borderRadius : 10,
}} > { text } </ button >
}
function App (){
return (
< div >
< Btn text =" Save changes " />
< Btn text =" Continue " big ={ false } />
</ div >
);
}
const root = document . getElementById (" root " );
ReactDOM . render (< App /> , root );
</ script >
</ html >
------------------------------------------------------------------------------------------------------------------------------------------------------------
해당 Btn에 추가되는 onClick = {changeValue}은 eventListener가 아님. 단지 props이름 중 하나일 뿐.
동작하게 하려면 html 태그에 직접 추가해야 함.
function App (){
const [ value , setValue ] = React . useState (" Save Changes " );
const changeValue = () => setValue (" Revert Changes " )
return (
< div >
< Btn text ={ value } onClick = { changeValue } />
< Btn text =" Continue " />
</ div >
);
}
->html 태그를 선언해놓은 Btn 함수로 가서 매개변수로 props 이름을 받은 후
function Btn ({ text , onClick})
->html tag <button />에 명시해줘야 동작함.
< button
onClick ={onClick }
***불필요한 re-render를 React.memo()로 관리하기***
원래 부모 component state에 변화가 생기면, 자식 컴포넌트 전체가 re-render가 일어남.
이 경우 state 변화가 없는 자식 component들도 함께 rerender가 일어나는데, 이 경우 React.memo()를 이용해
prop 변경이 일어난 부분만 rendering 시킬 수 있음.
* React.memo() 컴포넌트가 React.memo()로 wrapping 될 때, React는 컴포넌트를 렌더링하고 결과를 Memoizing 함. 그리고 다음 렌더링이 일어날 때 props가 같다면, React는 Memoizing된 내용을 재사용 함.
<! DOCTYPE html >
< html >
< body >
< div id =" root " ></ div >
</ body >
< script type = " text/babel " >
//flipped인 상태: hours를 입력받는 상태(!flipped = min을 입력받는 상태)
function Btn ({ text , changeValue }){
console . log (text , " was rendered. " );
return (
< button
onClick ={ changeValue }
style ={{
backgroundColor : " tomato ",
color :" white ",
padding : " 10px 20px ",
border : 0 ,
borderRadius : 10 ,
}} > { text } </ button >
)
}
const MemorizedBtn = React . memo (Btn );
function App (){
const [ value , setValue ] = React . useState (" Save Changes " );
const changeValue = () => setValue (" Revert Changes " )
return (
< div >
< MemorizedBtn text ={ value } changeValue = { changeValue } />
< MemorizedBtn text =" Continue " />
</ div >
);
}
const root = document . getElementById (" root " );
ReactDOM . render (< App /> , root );
</ script >
</ html >
보다시피, Revert Change만 re-render가 일어나고, Continue에선 re-render가 마지막에 일어나지 않았음.
------------------------------------------------------------------------------------------------------------------------------------------
React에서는 prop의 type이 잘못전달되었어도, 개발자가 뭘 전달하고자 하는지 파악하지 못하므로, 오류메시지가 뜨지 않음. 아래와 같이 propTypes를 사용자가 직접 지정해 다른 타입이 입력되면, 에러창을 띄워줄 수 있음.
이는 오류감지와 의도치않은 실수를 미연에 방지해줌.
const MemorizedBtn = React . memo (Btn );
MemorizedBtn . propTypes = {
//props의 type이 무엇이고 어떤 형태여야하는지 정의
text : PropTypes . string ,
fontSize : PropTypes . number . isRequired ,
}