⭐️ react에서는 html과 달리 이벤트에 camelCase를 사용한다.
html에서는
onclick
이라고 나타냈지만 react에서는onClick
이라고 쓴다.
onClick
이벤트는 특정 element가 클릭
됐을 때 정의된 함수를 호출하는 방식으로 사용한다.
onChange
이벤트는 특정 element에 변화
가 생겼을 때 정의된 함수를 호출하는 방식으로 사용한다.
onMouseMove
이벤트는 특정 tag 영역 안에서 마우스 커서가 움직일 때 발생한다.onMouseOver
이벤트는 특정 tag 영역 안에 마우스 커서가 진입할 때 발생한다.onMouseOut
이벤트는 특정 tag 영역 안에 마우스 커서가 진입했다가 벗어날 때 발생한다.onKeyDown
이벤트는 키를 눌렀을 때 동작한다.onKeyPress
이벤트는 키를 눌렀을 때 동작한다.onKeyUp
이벤트는 눌려 있던 키에서 손을 뗐을 때 동작한다.onSubmit
이벤트는 <form>
태그에 사용한다. <input>
태그를 클릭하거나 enter를 누르면 발생한다.
Ref
는 컴포넌트 내부의 요소에 접근할 때 사용된다. Ref를 사용하면 DOM 요소를 직접 조작하거나, 컴포넌트 인스턴스에 접근할 수 있다.
useRef
useRef
는 React에서 Ref 객체를 생성하는 Hook이다.
useRef를 사용하면 클래스 컴포넌트의this.refs
와 같은 기능을 함수형 컴포넌트에서 사용할 수 있다.const myRef = useRef(initialValue);
import React, { useRef } from 'react'; // import 하기
function MyComponent() {
const inputRef = useRef(null); // input 참조
const handleClick = () => {
inputRef.current.focus(); // 버튼 클릭시 focus 효과
}
return (
<div>
<input type="text" ref={inputRef} /> // 참조할 요소
<button onClick={handleClick}>포커스</button>
</div>
);
}
커링(Currying) 함수는 함수를 반환하는 함수로, 여러 개의 인수를 받는 함수를 하나의 인수만 받는 함수들의 중첩 함수로 나누는 것이다.
이를 통해 함수의 재사용성을 높일 수 있다.
function multiply(x) {
return function(y) {
return x * y;
}
}
// 위 함수를 ES6 화살표 함수로 간단히 표현하면 다음과 같다.
const multiply = x => y => x * y;
const double = multiply(2); // (y) => 2 * y
const triple = multiply(3); // (y) => 3 * y
console.log(double(4)); // 8
console.log(triple(4)); // 12
커링과 같이 함수 자체를 인자로 받거나 반환하는 함수를 고차 함수
라고 한다.
이와 비슷하게 컴포넌트를 인자로 받거나 반환하는 함수를 고차 컴포넌트
라고 한다.
MyComponentWithLoadingIndicator
는 withLoadingIndicator
함수를 실행시킨다.withLoadingIndicator
함수는 props에서 isLodaing과 나머지 데이터를 분리해 isLoading이 true일 때 로딩 문구를 return하고, 그 외에는 Component
에 나머지 데이터를 전달한다.Component
는 나머지 데이터를 props로 받아서 데이터의 title과 content를 보여준다.import React from 'react';
function withLoadingIndicator(Component) {
return function WithLoadingIndicator(props) {
const { isLoading, ...rest } = props;
if (isLoading) {
return <div>Loading...</div>;
}
return <Component {...rest} />;
}
}
function MyComponent(props) {
const { data } = props;
return (
<div>
<h1>{data.title}</h1>
<p>{data.content}</p>
</div>
);
}
const MyComponentWithLoadingIndicator = withLoadingIndicator(MyComponent);
function App() {
const isLoading = true;
const data = { title: 'Hello', content: 'World!' };
return (
<MyComponentWithLoadingIndicator isLoading={isLoading} data={data} />
);
}
props
를 사용하면 데이터를 부모 컴포넌트에서 자식 컴포넌트로 전송할 수 있다.
그런데 만약 손자 컴포넌트가 부모 컴포넌트의 데이터를 필요로 한다면, 자식 컴포넌트가 중간에서 데이터를 전달해야 한다.(부모 -> 자식 -> 손자
로 전달)
이때 자식 컴포넌트가 부모 컴포넌트의 데이터가 필요하지 않은 상황이라면 불필요한 코드를 작성하게 된다.(관계가 깊어질수록 전달하기가 매우 번거로워진다.)
컨텍스트
는 데이터의 공급자와 소비자를 정의하고 데이터가 필요한 컴포넌트만 사용할 수 있게 구현할 수 있다.
useContext
일반적으로 컨텍스트는 여러 컴포넌트에서 공유해야 하는 데이터를 저장하고, 이를 자식 컴포넌트에서 사용할 수 있도록 한다. 컨텍스트는 전역으로 사용할 수 있어야 하기 때문에, 보통 최상위 컴포넌트에 위치한다.
import {createContext, useState} from 'react'; // createContext import하기
const themes = {
light: {
foreground: '#000000',
background: '#eeeeee'
},
dark: {
foreground: '#ffffff',
background: '#222222'
}
};
// ThemeContext 객체를 만들어 초기값으로 themes.light 전달
export const ThemeContext = createContext(themes.light);
// ThemeProvider 생성
export const ThemeProvider = ({children}) => {
const [theme,setTheme] = useState(themes.light);
return(
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
)
}
createContext
를 이용해 컨텍스트를 만든다.provider
를 만든다.ThemeContext.Provider
컴포넌트를 사용해야 한다. ThemeContext.Provider
컴포넌트의 value prop에는 ThemeContext 객체에서 사용할 값을 지정할 수 있다.import {useContext} from 'react'; // useContext import하기
import {ThemeContext} from '../ThemeContext'; // 사용할 컨텍스트 import 하기
function ChildComponent() {
const theme = useContext(ThemeContext); // useContext를 이용해 컨텍스트에서 데이터 가져오기
return (
<div style={{ color: theme.foreground, backgroundColor: theme.background }}>
This is a child component
</div>
);
}
export default ChildComponent;
useContext
와 사용할 컨텍스트
를 import 해온다.useContext
를 이용해 컨텍스트에서 데이터를 가져와 사용한다.ThemeContext.Provider
컴포넌트를 사용하지 않고, useContext Hook을 사용하면, 초기값이 undefined로 설정되어 에러가 발생할 수 있다.props는 데이터가 부모에서 자식 컴포넌트로 단방향으로만 이동할 수 있다. 하지만 컨텍스트를 사용하면 자식 컴포넌트에서 부모 컴포넌트의 데이터를 변경할 수 있다.
-> Provider 컴포넌트에서 상태를 변경하는 함수를 작성하고 이를 value로 전달하면, 자식 컴포넌트에서 전달받은 함수를 이용해 부모 데이터를 변경할 수 있다.
import { createContext, useState } from 'react';
const MyContext = createContext();
const ParentComponent = () => {
const [state, setState] = useState({
name: 'John',
age: 30,
});
const updateState = (name, age) => {
setState({
...state,
name,
age
});
};
return (
<MyContext.Provider value={{ state, updateState }}>
<ChildComponent />
</MyContext.Provider>
);
};
export default ParentComponent;
업데이트 함수의 setState안에
...state
를 쓰는 이유
- setState 함수를 사용하여 상태를 업데이트할 때, 이전 상태를 완전히 덮어쓰는 대신, 기존 상태의 일부를 변경하고자 할 때 사용된다.
...state
는 객체 분해 할당을 사용하여, state 객체의 모든 속성을 현재 상태로 복사하고 새로운 값을 할당하여 변경된 상태를 만든다.- 위 코드에서는 기존 state 객체의 모든 속성을
...state
로 복사한 후, name과 age만 새로운 값으로 업데이트하여 새로운 객체를 생성한다.- 이렇게 하면 기존 상태를 완전히 덮어쓰지 않고, 일부 속성만 변경할 수 있기 때문에 효율적인 상태 업데이트가 가능하다.
import { useContext } from 'react';
import MyContext from './MyContext';
const ChildComponent = () => {
const { state, updateState } = useContext(MyContext);
const handleClick = () => {
updateState('Jane', 25);
// 컨텍스트로부터 전달받은 update함수를 이용해 부모 데이터 갱신
};
return (
<div>
<p>{state.name}</p>
<p>{state.age}</p>
<button onClick={handleClick}>Update State</button>
</div>
);
};
export default ChildComponent;
// 버튼을 클릭하면 'John', 30 에서 'Jane', 25로 바뀐다.
redux는 컨텍스트와 마찬가지로 데이터를 필요한 컴포넌트에서만 요청해 사용할 수 있다.
스토어
라는 곳에서 관리한다.npm install --save redux
redux는 데이터를 스토어 > 컴포넌트 > 액션 > 리듀셔 > 다시 스토어의 과정을 통해 변경한다.
index.js
import {createStore} from 'redux'; // 스토어 생성 함수
import reducers from './reducers'; // 데이터 초깃값 설정하고 데이터 변경해주는 함수
const store = createStore(reducers); // store 생성
const listener = () => {
ReactDOM.render(
<App store={store}/>,
document.getElementById('root')
);
};
store.subscribe(listener);
// store를 구독하면 store 데이터에 변화가 있을 때 listener 내부의 render 함수를 실행하고 변경된 데이터를 렌더링한다.
listener(); // 초기 렌더링을 위해 수동으로 render 함수 실행
redux 파트 79 ~ 84는 나중에 추가.
쿠키
란 사용자가 접속한 웹 사이트의 서버를 통해 사용자 컴퓨터에 설치되는 정보를 말한다.
쿠키는 사용자 정보를 저장하거나 마케팅을 위한 목적으로 사용될 수 있다.
npm install react-cookies --save
save 함수의 세 가지 파라미터 : 쿠키의 키(userid), 쿠키 값(Doozuu), 쿠키 옵션
import React from "react";
import { Component } from "react";
import cookie from 'react-cookies'; // import
class R085_cookieSave extends Component {
componentDidMount() {
const expires = new Date()
expires.setMinutes(expires.getMinutes() + 60) // 현재 시간으로부터 60분 후 만료
cookie.save('userid' , "Doozuu" ,{
path : '/', // 쿠키값을 저장하는 서버 경로
expires, // 쿠키의 유효시간
// secure : true // https인 경우에만 쿠키 저장
// httpOnly : true // document.cookie로 쿠키 접근하는 것 방지
});
}
render () {
return (
<><h3>react-cookies Save</h3></>
)
}
}
export default R085_cookieSave;
save
함수가 쿠키를 key-value 쌍으로 저장하는 함수였다면, load
함수는 웹 브라우저에 남아 있는 쿠키에 key로 접근해 value를 가져오는 함수다.
cookie.load(key)
: key에 해당하는 value를 가져온다.
쿠키가 저장되기까지 충분한 시간을 두기 위해 setTimout을 사용한다.
import React from "react";
import { Component } from "react";
import cookie from 'react-cookies'; // import
class R085_cookieSave extends Component {
componentDidMount() {
const expires = new Date()
expires.setMinutes(expires.getMinutes() + 60) // 현재 시간으로부터 60분 후 만료
cookie.save('userid' , "Doozuu" ,{
path : '/', // 쿠키값을 저장하는 서버 경로
expires, // 쿠키의 유효시간
// secure : true // https인 경우에만 쿠키 저장
// httpOnly : true // document.cookie로 쿠키 접근하는 것 방지
});
setTimeout(function(){
alert(cookie.load('userid')) // 1초 후 Doozuu 출력
},1000);
}
render () {
return (
<><h3>react-cookies Save</h3></>
)
}
}
export default R085_cookieSave;
remove
함수는 웹 브라우저에 남아 있는 쿠키에 key로 접근해 쿠키를 삭제하는 함수다.
import React from "react";
import { Component } from "react";
import cookie from 'react-cookies'; // import
class R085_cookieSave extends Component {
componentDidMount() {
const expires = new Date()
expires.setMinutes(expires.getMinutes() + 60) // 현재 시간으로부터 60분 후 만료
cookie.save('userid' , "Doozuu" ,{
path : '/', // 쿠키값을 저장하는 서버 경로
expires, // 쿠키의 유효시간
// secure : true // https인 경우에만 쿠키 저장
// httpOnly : true // document.cookie로 쿠키 접근하는 것 방지
});
setTimeout(function(){
cookie.remove('userid', { path: '/'}); // 1초 후 useid의 쿠키 값 삭제
}, 1000);
setTimeout(function(){
alert(cookie.load('userid')) // 1초 후 Doozuu 출력
},1000);
}
render () {
return (
<><h3>react-cookies Save</h3></>
)
}
}
export default R085_cookieSave;
라우팅
이란, 호출되는 url에 따라 페이지 이동을 설정하는 것이다.
라우팅을 지원하는 패키지로 react-router-dom
이 있다.
react-router-dom
패키지는 BrowerRouter, Router, Link의 기능을 제공한다.
<App/>
을 BrowerRouter 태그로 감싸준다.)npm install --save react-router-dom
App.js
import React, {Component} from 'react';
import reactRouter from './reactRouter';
import reactRouter2 from './reactRouter2';
import {Route} from 'react-router-dom'; // import
class App extends Component{
render(){
return(
<div className="App">
<Route exact path='/' component={reactRouter} />
<Route exact path='/reactRouter2' component={reactRouter2} />
</div>
);
}
}
export default App;
Link는 a 태그와 동일하게 동작한다.
예시
<Link to={'/reactRouter2'}>reactRouter2</Link>
<react img>
태그 사용하기react에서는 require
문법을 사용해 이미지 경로를 할당해야 한다.
예시
<img src={require("../img/main/log_img.png") alt=""}/>
debounce
는 연속된 이벤트 호출이 일어나는 상황에 사용한다.
npm install --save lodash
import React, { Component } from 'react';
import { debounce } from 'lodash'; // import
class reactDebounce extends Component {
debounceFunc = debounce( () => {
console.log("Debounce API Call");
}, 1000);
render() {
return (
<>
<h2> 검색어 입력 </h2>
<input type="text" onChange={this.debounceFunc} />
</>
)
}
}
export default reactDebounce;
throttle도 debounce와 동일하게 시간 조건을 추가해 실행 횟수를 제한한다.
차이점은 debounce가 연속된 이벤트 중 마지막 이벤트가 발생한 시점부터 특정 시간이 지났을 때 동작한다면, throttle은 발생한 이벤트 수와 관계없이 지정한 시간 단위당 최대 한 번만 동작한다는 것이다.
1초의 실행 시간 간격을 할당한다면, throttle 함수는 1초마다 0개 또는 1개의 로그를 출력한다.
만약 react 라는 검색어를 0초(r), 0.3초(e), 0.5초(a), 1.1초(c), 2초(t)에 입력했다면, throttle은 0초(r), 1초(rea), 2초(react)에 1초 단위로 데이터 호출 코드를 실행한다.