[React] Hooks & Context - 1
1. Basic Hooks
- Component 사이에서 상태와 관련된 로직을 재사용하기 어려움
- 컨테이너 방식 말고, 상태와 관련된 로직
- 복잡한 Component들은 이해하기 어려움
- Class는 사람과 기계를 혼동시킴
- 컴파일 단계에서 코드를 최적화하기 어렵게 만듦
- this.state는 로직에서 레퍼런스를 공유하기 때문에 문제가 발생할 수 있음
// src/components/Example1.jsx
import React from "react";
export default class Example1 extends React.Component {
state = { count: 0 };
render() {
const { count } = this.state;
return (
<div>
<p>You clicked {count} times</p>
<button onClick={this.click}>Click me</button>
</div>
);
}
click = () => {
this.setState({ count: this.state.count + 1 });
};
}
// src/App.js
import logo from "./logo.svg";
import "./App.css";
import Example1 from "./components/Example1";
function App() {
return (
<div className="App">
<header className="header">
<img src={logo} className="logo" alt="logo" />
<Example1 />
</header>
</div>
);
}
// src/components/Example2.jsx
import React from "react";
export default function Example2() {
const [count, setCount] = React.useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={click}>Click me</button>
</div>
);
function click() {
setCount(count + 1);
}
}
// src/App.js
import logo from "./logo.svg";
import "./App.css";
import Example1 from "./components/Example1";
import Example2 from "./components/Example2";
function App() {
return (
<div className="App">
<header className="header">
<img src={logo} className="logo" alt="logo" />
<Example1 />
<Example2 />
</header>
</div>
);
}
// src/components/Example3.jsx
import React from "react";
// useState => count
// useState => { count: 0 }
export default function Example3() {
const [state, setState] = React.useState({ count: 0 });
return (
<div>
<p>You clicked {state.count} times</p>
<button onClick={click}>Click me</button>
</div>
);
function click() {
setState((state) => ({
count: state.count + 1,
}));
}
}
// src/App.js
import logo from "./logo.svg";
import "./App.css";
import Example1 from "./components/Example1";
import Example2 from "./components/Example2";
import Example3 from "./components/Example3";
function App() {
return (
<div className="App">
<header className="header">
<img src={logo} className="logo" alt="logo" />
<Example1 />
<Example2 />
<Example3 />
</header>
</div>
);
}
- useState
- state를 대체 할 수 있음
- useEffect
- Lifecycle 훅을 대체 할 수 있음
- componentDidMount
- componentDidUpdate
- componentWillUnmount
- Lifecycle 훅을 대체 할 수 있음
// src/components/Example4.jsx
import React from "react";
export default class Example4 extends React.Component {
state = { count: 0 };
render() {
const { count } = this.state;
return (
<div>
<p>You clicked {count} times</p>
<button onClick={this.click}>Click me</button>
</div>
);
}
componentDidMount() {
console.log("componentDidMount", this.state.count);
}
componentDidUpdate() {
console.log("componentDidUpdate", this.state.count);
}
click = () => {
this.setState({ count: this.state.count + 1 });
};
}
// src/App.js
import logo from "./logo.svg";
import "./App.css";
import Example1 from "./components/Example1";
import Example2 from "./components/Example2";
import Example3 from "./components/Example3";
import Example4 from "./components/Example4";
function App() {
return (
<div className="App">
<header className="header">
<img src={logo} className="logo" alt="logo" />
<Example1 />
<Example2 />
<Example3 />
<Example4 />
</header>
</div>
);
}
// src/components/Example5.jsx
import React from "react";
export default function Example5() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
console.log("componentDidMount");
return () => {
// cleanup
// componentWillUnmount
};
}, []);
React.useEffect(() => {
console.log("componentDidMount & componentDidUpdate by count", count);
return () => {
// cleanup
console.log("cleanup by count", count);
};
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={click}>Click me</button>
</div>
);
function click() {
setCount(count + 1);
}
}
// src/App.js
import logo from "./logo.svg";
import "./App.css";
import Example1 from "./components/Example1";
import Example2 from "./components/Example2";
import Example3 from "./components/Example3";
import Example4 from "./components/Example4";
import Example5 from "./components/Example5";
function App() {
return (
<div className="App">
<header className="header">
<img src={logo} className="logo" alt="logo" />
<Example5 />
</header>
</div>
);
}
2. Custom Hooks
// src/hooks/useWindowWidth.js
import { useState, useEffect } from "react";
export default function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const resize = () => {
setWidth(window.innerWidth);
};
window.addEventListener("resize", resize);
return () => {
window.removeEventListener("resize", resize);
};
}, []);
return width;
}
// src/App.js
import logo from "./logo.svg";
import "./App.css";
import Example5 from "./components/Example5";
import useWindowWidth from "./hooks/useWindowWidth";
function App() {
const width = useWindowWidth();
return (
<div className="App">
<header className="header">
<img src={logo} className="logo" alt="logo" />
<Example5 />
{width}
</header>
</div>
);
}
// src/hocs/withHasMounted.jsx
import React from "react";
export default function withHasMounted(Component) {
class NewComponent extends React.Component {
state = {
hasMounted: false,
};
render() {
const { hasMounted } = this.state;
return <Component {...this.props} hasMounted={hasMounted} />;
}
componentDidMount() {
this.setState({ hasMounted: true });
}
}
NewComponent.displayName = `withHasMounted(${Component.name})`;
return NewComponent;
}
// src/App.js
import logo from "./logo.svg";
import "./App.css";
import useWindowWidth from "./hooks/useWindowWidth";
import withHasMounted from "./hocs/withHasMounted";
function App({ hasMounted }) {
const width = useWindowWidth();
console.log(hasMounted);
return (
<div className="App">
<header className="header">
<img src={logo} className="logo" alt="logo" />
{width}
</header>
</div>
);
}
export default withHasMounted(App);
// src/hooks/useHasMounted.js
import { useState } from "react";
export default function useHasMounted() {
const [hasMounted, setHasMounted] = useState(false);
useEffect(() => {
setHasMounted(true);
}, []);
return hasMounted;
}
// src/App.js
import logo from "./logo.svg";
import "./App.css";
import useWindowWidth from "./hooks/useWindowWidth";
import withHasMounted from "./hocs/withHasMounted";
import useHasMounted from "./hooks/useHasMounted";
function App({ hasMounted }) {
const width = useWindowWidth();
const hasMountedFromHooks = useHasMounted();
console.log(hasMounted, hasMountedFromHooks);
return (
<div className="App">
<header className="header">
<img src={logo} className="logo" alt="logo" />
{width}
</header>
</div>
);
}
export default withHasMounted(App);
댓글남기기