부모의 이벤트 함수를 자식에서 호출하게끔 하는 방식을 통해서 props를 활용한다.
해당 방법을 통해 자식 -> 부모로 데이터 전달이 가능하다.
부모에서 이벤트함수를 선언 및 정의
자식 컴포넌트 호출시 속성명={이벤트함수} 로 이벤트함수 전달
2-1. 여기서 속성명은 이벤트명명 규칙에 영향을 받지 않는다.
자식에서 props에 전달된 이벤트함수 전달받기
자식에서 이벤트함수 람다함수 형태로 호출, 데이터 전달 onClick={()=>이벤트함수(전달할 데이터)}
이벤트 전달 속성명과 받는 변수명 일치해야함
import React from 'react';
import TapButton from './components/TapButton';
function App(props) {
var x="변경될 데이터";
function handleEvent(v) {
console.log("handleEvent: "+ v);
x = "x변경됨 " + v ;
console.log(x);
}
console.log("부모 x: ", x);
return (
<div>
<TapButton eventFunc={handleEvent} children>
Java
</TapButton>
<TapButton eventFunc={handleEvent}>
SQL
</TapButton>
<TapButton eventFunc={handleEvent}>
React
</TapButton>
<TapButton eventFunc={handleEvent}>
Vue
</TapButton>
x 값 : {x}
</div>
);
}
export default App;
import React from 'react';
function TapButton(props) {
const { eventFunc, children } = props
return (
<div>
<button onClick={()=>eventFunc(children)}>{children}</button>
</div>
);
}
export default TapButton;
함수에서 x라는 변수가 변경되어도 화면에 출력하는 x가 변경되지 않는다?
이유 : App 컴포넌트는 한번만 랜더링 되기 때문이다 ?
그래서 hook이라는 것이 필요하다?
왜 쓸까...
e.preventDefault()
e.stopPropagation()
리액트는 기본적으로 변수가 변경되어도 화면이 재랜더링되지 않는다.
그래서 useState() 메서드를 사용하여 변수와 변경함수를 설정해줄 수 있다.
이 설정함수를 통해 변수를 변경시 변경+랜더링 효과를 함께 준다.
- 임포트 :
import {useState} from ‘react’- 초기화 :
const [변수, 변수변경함수] = useState(초기값)
원래는 다음과 같이 해야하지만,const numberState = useState(0); const number = numberState[0]; const setNumber = numberState[1];배열 비구조화 할당을 통하여 각 원소를 추출해준것입니다.
setNumber(number+1)후
number값은 갱신값이 아닌 이전값으로 출력
이유는 리액트가 변경사항을 스케줄함(변경+리랜더링 : 비동기)
따라서 스케줄이 끝난 후에야 변경사항을 얻을 수 있으나
현재 스케줄 전에 console.log했기 때문에 이전 값이 출력됨
스케줄 로직에 대해서 숙지해야할듯하다.
useState를 이용한 상태 업데이트는 비동기적이기 때문에 변경 사항이 즉시 반영되지 않는다.
useState의 업데이터는 이전 값을 기억(with 클로저)하고 있다가, 비동기 요청에서 사용 가능한 값으로 바꾼다.
함수형 컴포넌트는 상태변경이 일어나면 함수를 다시 호출해 렌더링을 해야한다.
즉, useState를 통해 업데이트할 때는 리렌더링이 필요하다.
const onDecrease = () => {
setNumber(prevNumber => prevNumber - 1);
}
onIncrease 와 onDecrease 에서 setNumber 를 사용 할 때 그 다음 상태를 파라미터로 넣어준것이 아니라, 값을 업데이트 하는 함수를 파라미터로 넣어주었습니다.
함수형 업데이트는 주로 나중에 컴포넌트를 최적화를 하게 될 때 사용하게 됩니다. 지금 당장은 함수형 업데이트란게 있는 것 정도만 이해해두시면 충분합니다. 이게 왜 최적화랑 관련이 되어있는지는 나중에 알아보도록 할게요.
import React, { useState } from 'react';
function App(props) {
const numberState = useState(0);
const number = numberState[0];
const setNumber = numberState[1];
function plus(){
setNumber(number => number+1);
}
function minus(){
if(number>0)
setNumber(number => number+-1);
}
return (
<div>
<h1>{number}</h1>
<button onClick={plus}>+</button>
<button onClick={minus}>-</button>
</div>
);
}
export default App;
import React, { useState } from 'react';
function App(props) {
const [isEditing, setIsEditing] = useState(true);
function handleEvent(){
setIsEditing(()=> !isEditing);
console.log(isEditing);
}
let tag = (
<>
<span>홍길동</span>
<button onClick={handleEvent}>Edit</button>
</>
);
if(!isEditing) {
tag = (
<>
<input></input>
<button onClick={handleEvent}>Save</button>
</>
)
}
console.log("App호출");
return (
<div>
{tag}
</div>
);
}
export default App;
불변 변수는 이름에 새로 값을 묶을 수 없는 것을 의미한다.
state에 저장된 배열, json객체 등은 요소의 직접적인 수정이 불가능하다.
기본적으로 덮어쓰기만이 가능하다.
기존의 배열주소값이 아닌 새로운 객체주소를 가진 값을 덮어쓰는 것만이 가능.
그래서 만약 수정이 필요하다면 아래와 같은 방식으로 새롭게 배열을 만드는 방식으로 수정기능을 이용할 수 있다.
const [number, setNumber] = useState({n:0}); //json
const onIncreaseError = ()=>{
number.n = number.n+1;
setNumber(number);
console.log("onIncrease : ", number.n);
}
const onIncrease = ()=>{
setNumber({...number, n: number.n+1});
console.log("onIncrease : ", number.n);
}
const onDecrease = () =>{
const new_number = {...number};
console.log(number === new_number); //false,
const new_number2 = {...number, n: number.n-1};
setNumber(new_number2) //덮어쓰기
console.log("onDecrease : ", number.n);
}