์ด๋ ํ ๋ฐ์ดํฐ๋ฅผ ์ ๋์ ์ผ๋ก ์ ๋ฌํ๊ธฐ ์ํ์ฌ state๋ฅผ ์ฌ์ฉํ๋ค.
state๋ ํ ๋ถ๋ถ์์๋ง ์ฐ๋ ๊ฒ์ด ์๋๋ผ ์ฌ๋ฌ ๋ถ๋ถ์ผ๋ก ์ ๋ฌํ์ฌ ์ฌ์ฉํ๋ค.
์ด๋ฌํ state๋ฅผ ์ด๋ป๊ฒ ํจ์จ์ ์ผ๋ก ์ฌ๋ฌ ๋ถ๋ถ์์ ์ธ ์ ์๋์ง ์์๋ณด์.
stateful logic์ด๋ state๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋๋ฅผ ๋งํ๋ค.
stateful logic sharing์ด๋ ์ฌ๋ฌ ์ปดํฌ๋ํธ๋ค์ด ์ด๋ ํ state๋ฅผ ๊ณต์ ํ์ฌ ์ฐ๋ ๊ฒ์ ๋งํ๋ค.
stateful logic sharing์ ์ํ์ฌ props๋ก state๋ฅผ ์ ๋ฌํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
App.js
import React, { Component } from "react";
import Passprops from "./Passprops";
import Passprops2 from "./Passprops2";
class App extends Component {
state = {
number: 0,
};
render() {
return (
<div>
<Passprops number={this.state.number} />
<Passprops2 number={this.state.number} />
</div>
);
}
}
export default App;
Passprops.js
import React, { Component } from "react";
class Passprops extends Component {
render() {
return <div>Passprops1:{this.props.number}</div>;
}
}
export default Passprops;
Passprops2.js
import React, { Component } from "react";
class Passprops2 extends Component {
render() {
return <div>Passprops2:{this.props.number}</div>;
}
}
export default Passprops2;
๋ค์๊ณผ ๊ฐ์ด App.js์ ์๋ state๊ฐ์ ์ฌ๋ฌ ์ปดํฌ๋ํธ๊ฐ ๊ณต์ ํ ์ ์๋ค.
(stateful logic sharing)
ํ์ง๋ง ๋ง์ฝ ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ ๋ค๋ฅด๋ค๋ฉด state๋ฅผ ์ธ ์ ์๋ค.
์ฆ, ์์ ์๋ฅผ ์ฐธ๊ณ ํ์๋ฉด App.js์์ ์ปดํฌ๋ํธ๋ฅผ ์ธ๊ธํ์ง ์๋๋ค๋ฉด ๊ทธ ์ปดํฌ๋ํธ๋ App.js์ ์๋ state๋ฅผ ์ธ ์ ์๋ ๊ฒ์ด๋ค.
์ด๋ฅผ ์ํ ๋ฐฉ๋ฒ์ผ๋ก HOCs์ render props๊ฐ ์ ์๋๋ค.
HOCs๋ ์ด๋ ํ ์ปดํฌ๋ํธ๋ฅผ ๋์ฑ ํฅ์๋ ์ปดํฌ๋ํธ๋ก ๋ณํํด์ฃผ๋ ํจ์์ด๋ค.
const EnhancedComponent = higherOrderComponent(WrappedComponent);
๋ค์์ stateful logice sharing์ ์ํ HOCs์ ํจํด ์์์ด๋ค.
App.js
import React from "react";
function withCounter(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
increment = () => {
this.setState((prevState) => ({ count: prevState.count + 1 }));
};
render() {
return <WrappedComponent count={this.state.count} increment={this.increment} {...this.props} />;
}
};
}
class Component1 extends Component {
render() {
const { count, increment } = this.props;
return (
<div>
<button onClick={increment}>Clicked {count} times!</button>
</div>
);
}
}
export const DerivedComponent = withCounter(Component1);
index.js
import React from "react";
import ReactDOM from "react-dom";
import { DerivedComponent } from "./App";
ReactDOM.render(
<React.StrictMode>
<DerivedComponent />
</React.StrictMode>,
document.getElementById("root")
);
์์ ๊ฐ์ด withCounterํจ์(HOCsํจ์)๋ ์ปดํฌ๋ํธ(Component1)๋ฅผ ์ธ์๋ก ๋ฐ๋๋ค.
์ปดํฌ๋ํธ(Component1)๋ state๋ฅผ ์ ๋ฌ๋ฐ์ ์ฌ์ฉํ ์ ์๋ค.
HOCsํจ์(withCounter)์ ๋ฐํ๊ฐ์ state๋ฅผ ์ ๋ฌ๋ฐ๋ ์ปดํฌ๋ํธ(DerivedComponent)์ ํ ๋นํ๋ค.
์ด์ ๊ฐ์ด HOCs๋ state๋ฅผ ์ ๋ฌํด์ฃผ๋ ํจ์๋ก์ง์ ๊ตฌ์ฑํด์ฃผ์ด ํจ์์ ์ธ์๋ก ์ปดํฌ๋ํธ๋ง ๋์ ํด์ฃผ๋ฉด state๋ฅผ ์ฌ์ฉํ๊ฒ ํด์ฃผ๋ stateful logic sharing์ ๋ฐฉ๋ฒ์ค ํ๋์ด๋ค.
๋๋ถ์ด HOCs ํจํด์ stateful logic sharing๋ฟ ์๋๋ผ ๋ค๋ฅธ ํจ์จ์ ์ธlogic์ ๊ตฌ์ฑํ๊ธฐ์ํด์๋ ์ฐ์ธ๋ค.
HOCsํจ์๋ฅผ ๊ตฌ์ฑํ ๋ ์ฃผ์ํด์ผํ ์ฌํญ๋ค์ ๋ค์๊ณผ ๊ฐ๋ค.
HOC ๋ด๋ถ์์ ์ปดํฌ๋ํธ์ ๋ณํ์ํค์ง ์์์ผํ๋ค.
์ด๋ ์ปดํฌ๋ํธ๋ฅผ ๋ฐ๋ก ์ฌ์ฉํ ๋์๋ ํด๋น ์ปดํฌ๋ํธ๊ฐ ์ํฅ์ ๋ฐ์ ์ ์๋ค.
render()์ HOCs๋ฅผ ์ฌ์ฉํ๋ฉด ์๋๋ค.
render()๋ ์ด์ ํธ๋ฆฌ์ ๋น๊ตํ์ฌ ์ด์ ๊ฒ์ unmountํ๊ณ ๋ณํ๋ ๊ฒ์ ๋ฐ์ํ๋๋ฐ ์ฌ๊ธฐ์ HOCs๋ก ๊ฐ์ผ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ ์ state๊ฐ์ด unmount๋๊ณ ํ์ ์ปดํฌ๋ํธ๋ค๋ unmount๋ ์ ์๋ค.
stateful logic sharing์ ๋๋ฒ์งธ ๋ฐฉ๋ฒ์ผ๋ก๋ render props๊ฐ ์๋ค.
render prop์ prop์ผ๋ก ๋ ๋ํ ๋ด์ฉ์ ํ ๋นํด์ฃผ๋ ๊ฒ์ด๋ค.
์์๋ ๋ค์๊ณผ ๊ฐ๋ค.
์ฐ์ Counter๋ผ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด์ค๋ค.
Counter.js
import React, { Component } from "react";
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return <div>{this.props.render(this.state.count, this.increment)}</div>;
}
}
export default Counter;
count๋ผ๋ state์ state๋ฅผ ๋ณ๊ฒฝํด์ฃผ๋ increment ํจ์๋ฅผ ๋ง๋ค์ด์ค๋ค.
๋ ๋๋ถ๋ถ์๋ ๋ถ๋ชจ์ปดํฌ๋ํธ์์ ์ธ๊ธํ render๋ผ๋ props๋ฅผ ๋ฐ์ ์ธ์๋ก count์ increment๋ฅผ ํ ๋นํด์ค๋ค.
๋ถ๋ชจ์ปดํฌ๋ํธ๋ ๋ค์๊ณผ ๊ฐ๋ค.
App.js
import React from "react";
import Counter from "./components/Counter";
import ButtonCounter from "./components/ButtonCounter";
// prop์ผ๋ก ๋ ๋๋งํ ๋ด์ฉ์ ์ ๋ฌ?
const App = () => {
return (
<div>
<Counter
render={(count, increment) => (
<ButtonCounter count={count} increment={increment} />
)}
/>
</div>
);
};
export default App;
๋ถ๋ชจ์ปดํฌ๋ํธ(App.js)์์๋ Counter ์ปดํฌ๋ํธ์ render๋ผ๋ props๋ฅผ ์ ๋ฌํด์ฃผ๊ณ ๋ด์ฉ์ ๋๊ฐ์ ์ธ์๋ฅผ ๊ฐ๋ ํจ์๋ฅผ ์ ๋ฌํด์ค๋ค.
ํจ์์ ๋ฐํ๊ฐ์ state๋ฅผ ์ ๋ฌ๋ฐ๋ ์๋ก์ด ์ปดํฌ๋ํธ(ButtonCounter)๋ฅผ ๋ฐํํด์ค๋ค.
ButtonCounter์ ๋ค์๊ณผ ๊ฐ๋ค.
ButtonCounter.js
import { Component } from "react";
class ButtonCounter extends Component {
render() {
const { count, increment } = this.props;
return <button onClick={increment}>Clicked {count} times!</button>;
}
}
export default ButtonCounter;
์ด์ฒ๋ผ ๋ถ๋ชจ์ปดํฌ๋ํธ์์ props๋ก ๋ ๋ํ ๋ด์ฉ์ ๋์ ์ผ๋ก ์ ๋ฌํด์ฃผ์ด ์ฌ๋ฌ ์ปดํฌ๋ํธ๊ฐ state sharing์ ํ ์ ์๋ค.
HOCs์ render props ๋ ๊ฐ์ง ๋ฐฉ๋ฒ ๋ค ์ ํด์ง API๊ฐ ์๋ ์ฌ์ฉ์๊ฐ ๋ง๋ค์ด์ ์ฐ๋ ํจํด์ด๋ค.
ํด๋์คํ ์ปดํฌ๋ํธ์์ state๋ฅผ ์ ๋ฌํ ์ปดํฌ๋ํธ๊ฐ ๋ง์ง ์๋ค๋ฉด ์ง์ ์ ์ผ๋ก state๋ฅผ props๋ก ์ ๋ฌํ์ฌ ์ฌ์ฉํ๋ฉด ๋์ง๋ง ์ ๋ฌํ ์ปดํฌ๋ํธ๊ฐ ๋ง๋ค๋ฉด ์ ๋๊ฐ์ง ๋ก์ง์ ์ด์ฉํ์ฌ ํจ์จ์ ์ผ๋ก state๋ฅผ ๊ณต์ ํ ์ ์๋๋ก ํด์ผ๊ฒ ๋ค.
ํ์ง๋ง ํจ์ํ ์ปดํฌ๋ํธ๋ ์ด๋ฌํ ์ ์ ๊ฐ์ ํ๊ธฐ ์ํ์ฌ HOOk์ด๋ผ๋ API๋ฅผ ์ ์ํ์๊ณ ์ด๋ฅผ ์ฌ์ฉํ๋ฉด ์์ ๊ฐ์ ๋ฌธ์ ์ ๋ค์ ๋ ๊ฐํธํ๊ฒ ํด๊ฒฐํ ์ ์๋ค.
์ฐธ์กฐ : stateful logic sharing