์ปดํฌ๋ํธ State
setState()
State and Lifecycle
์ด๋ฒคํธ ์ฒ๋ฆฌํ๊ธฐ
์๋กญ๊ฒ ์๊ฒ ๋ ๋ด์ฉ์ด๊ฑฐ๋ ์ดํดํ๊ธฐ ์ด๋ ค์ ๋ ๋ถ๋ถ๋ง ์ ๋ฆฌ
setState()๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ ๋ด์์ ๋น๋๊ธฐ์ ์ผ๋ก ์ํ๋๋ค.
setState()๊ฐ ๊ฐ์ ์ฃผ๊ธฐ ๋์ ์ฌ๋ฌ ๋ฒ ํธ์ถ๋๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ผ๊ด์ ์ผ๋ก ์ฒ๋ฆฌ๋ ์ ์๋ค.
const handleClick = () => {
this.setState({quantity: this.state.quantity + 1});
this.setState({quantity: this.state.quantity + 1});
};
์ด๋ ๋ค์ ์ฝ๋์ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํ๋ค.
// Object.assgin()์ ๊ฐ์ฒด๋ค์ ๋ชจ๋ ์ด๊ฑฐ ๊ฐ๋ฅํ ์์ฒด ์์ฑ์ ๋ณต์ฌํด ๋์ ๊ฐ์ฒด์ ๋ถ์ฌ๋ฃ์ ํ ์ด๋ฅผ ๋ฐํํ๋ ๋ฉ์๋์ด๋ค
Object.assign(
previousState, // ๋์ ๊ฐ์ฒด
{quantity: state.quantity + 1},
{quantity: state.quantity + 1}, // ๊ณ์ ๋ฎ์ด์ฐ๊ธฐํ ๋ฟ์ด๋ค
...
);
์ํ๋ ๋๋ก ๋ค์ state ๊ฐ์ด ์ด์ state ๊ฐ์ ๊ธฐ๋ฐํ๋๋ก ํ๊ธฐ ์ํด์๋ setState()์ ์ธ์๋ก ํจ์๋ฅผ ๋ฃ์ด์ค์ผ ํ๋ค.
const handleClick = () => {
this.setState((state) => {
return {quantity: state.quantity + 1};
});
};
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
์์ ๊ฐ์ ํจ์ ์ปดํฌ๋ํธ๋ฅผ class๋ก ๋ณํํ๋ค. (React ์ปดํฌ๋ํธ์ this ์ฐธ๊ณ )
cf. ์ฝ๋ฐฑ ํจ์ ๋ด๋ถ์์์ this๋, ํด๋น ์ฝ๋ฐฑํจ์์ ์ ์ด๊ถ์ ๋๊ฒจ๋ฐ์ ํจ์(์๋ ์์ ์ ๊ฒฝ์ฐ์๋ setInterval)๊ฐ ์ ์ํ ๋ฐ์ ๋ฐ๋ฅด๋ฉฐ, ์ ์ํ์ง ์์ ๊ฒฝ์ฐ์๋ ์ ์ญ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ค.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { date: new Date() };
this.handleState = this.handleState.bind(this); // 3. this๋ฅผ ๋ฐ์ธ๋ํด์คฌ๋ค
console.log(this); // Clock {...}
}
componentDidMount() { // ๐ก ์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ ๋๋ง ๋๋ฉด ํธ์ถ๋จ
this.timer = setInterval(this.handleState, 1000);
// 4. this๋ฅผ ๋ฐ์ธ๋ํ์ง ์์ผ๋ ค๋ฉด ์ฌ๊ธฐ์ ํ์ดํ ํจ์๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค
// () => this.handleState()
}
handleState() {
console.log(this); // 1. ์ฌ๊ธฐ์ this๋ ์ ์ญ ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์
this.setState((state) => { // 2. ์ฌ๊ธฐ์ ์ฝ๋๊ฐ ๋ฌธ์ ์์ด ์คํ๋๋๋ก ํ๊ธฐ ์ํด
return { date: new Date() };
});
}
UNSAFE_componentWillUnmount() { // ๐ก ์ปดํฌ๋ํธ์ ์ํด ์์ฑ๋ DOM์ด ์ญ์ ๋๋ฉด ํธ์ถ๋จ
clearInterval(this.timer);
console.log(this); // cf. ๋ค๋ฅธ ์๋ช
์ฃผ๊ธฐ ๋ฉ์๋๋ค ๋ด๋ถ์ this๋ Clock {...} ์ด๋ค
}
render() { // ๐ก ์ปดํฌ๋ํธ ๋ด์์ ๋ฐ๋์ ๊ตฌํ๋์ด์ผ ํ ์ ์ผํ ํ์ ๋ฉ์๋
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById("root")
);
ํน์ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ ์๋ ์๋ค.
const Clock = () => {
const [date, setDate] = useState(new Date());
const updateDate = () => {
setInterval(() => setDate(new Date()), 1000);
};
useEffect(updateDate, []); // ์ปดํฌ๋ํธ๊ฐ ์ฒ์ ๋ ๋๋ง ๋๋ฉด ์คํ๋จ
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {date.toLocaleTimeString()}.</h2>
</div>
);
};
const App = () => {
return (
<div>
<Clock />
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById("root")
);
ES6 class์ ๋ณธ๋ฌธ์ ๊ธฐ๋ณธ์ ์ผ๋ก strict mode์์ ์คํ๋๋ค.
์ด๋ฒคํธ ํธ๋ค๋ฌ ํจ์ ๋ด๋ถ์์์ this๋ ๋ฐ์ธ๋ฉ ํด์ฃผ์ง ์๋ ํ undefined์ ๊ฐ์ ๊ฐ์ง๋ค.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
this.handleClick = this.handleClick.bind(this); // this๋ฅผ ๋ฐ์ธ๋ํด์คฌ๋ค. ๋ง์ฝ this๋ฅผ ๋ฐ์ธ๋ํ์ง ์์๋ค๋ฉด
}
handleClick() {
console.log(this); // ์ฌ๊ธฐ์ this๋ undefined๊ฐ ๋์ด
this.setState(prevState => ({ // ์ด ์ฝ๋๋ฅผ ์คํํ ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๊ฒ์ด๋ค
isToggleOn: !prevState.isToggleOn
}));
}
add() {
console.log(this);
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
react controlled
react ๊ฐ์ ๋ฃ๊ธฐ