[REACT] ReactJS๋ก ์ํ ์น ์๋น์ค ๋ง๋ค๊ธฐ
(((((((((((๊ธฐ์ด์ด์ธ ๊ธ ์ฃผ์. ํ ๊ฐ์๋ฅผ ํ ํฌ์คํธ์ ์ ๋ฆฌํจ)))))))))))
๋น์ฅ ๊ธ์์ผ๋ถํฐ ๋ฆฌ์กํธ๋ฅผ ์จ์ผํ๋ค.
์ง์ง .. ํฐ์ผ๋ฌ๋ค.
์ด ๊ธ์ ๊ฐ์์ ๋ชฉ์ฐจ๋ฅผ ๊ทธ๋๋ก ๊ฐ์ ธ์์ ๊ทธ ์์๋๋ก ์ ๋ฆฌํ ์์ ์ด๋ค. ๋ชฉ์ฐจ๋ ๋ค์๊ณผ ๊ฐ๋ค.
๋ฌ๋์ปค๋ธ๊ฐ ๋์ react์ด๊ธฐ ๋๋ฌธ์ ์คํ๋ ค ๊ธฐ์ด๋ฅผ ํ์คํ ์ ๋ฆฌํด๋์ด์ผ ํ ๊ฒ ๊ฐ๋ค.
๊ทธ๊ฒ ๋ฐ๋ก ์ค๋์ด ๋๊ธธ ๋ฐ๋ผ๋ฉด์ ์์ํด๋ณธ๋ค.
11 STATE
#11.0 Class Components and State (10:11)
#11.1 All you need to know about State (07:55)
#11.2 Component Life Cycle (08:07)
#11.3 Planning the Movie Component (05:02)
1 [2021 UPDATE] INTRODUCTION
#1.1 โค๏ธ ๋ฌด๋ฃ ๊ฐ์ โค๏ธ
ํ์ด์ค๋ถ์ ์ฌ์ ํ react js ์ฌ์ฉํ๊ณ ์์ผ๋ฉฐ ์ฌ์ ํ ์ด์๋จ์๋ค. ํ๋ก ํธ์ค๋ ๊ฐ๋ฐ์๋ก์ ์ข์ ๋๊ตฌ๊ฐ ๋ ๊ฒ!
#1.2 Why React
์ react js๋ฅผ ๋ฐฐ์ฐ๋ ๊ฒ์ด ์ค์ํ์ง, ๊ทธ๋ฆฌ๊ณ ์ผ๋ง๋ ์์ ํ์ง
์ฒ์์ ๋งค์ฐ ์ํํ์ง๋ง ์ค๋๋ ์ ์์ฃผ ์ข์ ์ ํ.
1. ์ ๊ธฐ์ ์ ๋ฐฐ์ธ๋ ๋๊ฐ ์ด ๊ธฐ์ ์ ์ฌ์ฉํ๋ ์ง, ์ผ๋ง๋ ๊ท๋ชจ๊ฐ ํฐ ์ง ๋ด์ผํ๋ค. ์์ 1๋ง๊ฐ์ ์น ์ฌ์ดํธ์ค 44.76%๊ฐ ๋ฆฌ์กํธ๋ฅผ ์ฌ์ฉํ๋ค. ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ค๊ณ ๋ณด๋ฉด ๋จ.
์์ด๋น์ค๋น, ์ธ์คํ๊ทธ๋จ, ํ์ด์ค๋ถ, ๋ทํ๋ฆญ์ค๊ฐ ์ฌ์ฉ์ค
2.์ด๋ฐ ๊ฑฐ๋ํ ํ์ฌ์์ ์ฐ๊ตฌํ๋ ์ฌ๋์ ํ๋ก ํธ์๋๋ฅผ ํฌ๊ฒ ๋ฐ๊พธ๊ณ ์ถ์ง ์์ํ๋ค. ์์ฃผ ์์ ํ๊ฑฐ๋ ๊ทธ๋ด ์๊ฐ์ด ์์.
์์ ์ ์ธ๊ฒ์ ์ํ๋ค. ์ด๋ฐ ์ฌ๋๋ค์ด ์ด์ฉํ๋ ๊ฒ์ ๋ฐฐ์ฐ๋ ๊ฒ์ ์์ฃผ ์ข์ ์ ํ์ด ๋ ๊ฒ.
3. ํฐ ์ปค๋ฎค๋ํฐ๋ฅผ ๊ฐ๊ณ ์์. ์๋ฐ์คํฌ๋ฆฝํธ๋ ๋งค์ฐ ๋น์ทํ๊ธฐ ๋๋ฌธ. ๋๋ถ๋ถ ์๋ฐ์คํฌ๋ฆฝํธ ์์ ์.
์ดํ ๋ฆฌ์กํธ ๋ค์ดํฐ๋ธ์ ์ธ ์ ์์.
#1.3 Requirements
์๋ฐ์คํฌ๋ฆฝํธ ๊ธฐ์ด๊ฐ ์์ด์ผํจ. ๋ฐ๋๋ผ js ๋ก ํฌ๋กฌ์ฑ ๋ง๋ค๊ธฐ ํด์ค๋ผ๊ณ ํ์ง๋ง ์ด๋ฏธ ํด๋ดค๊ธฐ๋ ํ๊ณ .. pass
2 [2021 UPDATE] THE BASICS OF REACT
๋ฆฌ์กํธ๊ฐ ํด๊ฒฐํ๋ ค๊ณ ํ๋ ๋ฌธ์ ๋?
REACT JS๋ UI๋ฅผ interactive ํ๊ฒ ๋ง๋ค์ด์ค.
๋ฐ๋๋ผjs์ react ์ฝ๋๋ฅผ ๋น๊ต

1. html ๋ง๋ค๊ธฐ
2. javascript ๊ฐ์ ธ์ค๊ธฐ
3. event ๊ฐ์ง
4. ๋ฐ์ดํฐ ์ ๋ฐ์ดํธ
5. html์ ๋ฐ์ดํธ
์ด๋๋ก ์์ ํ๋ค๊ฐ ์์ฃผ ํผ๋์ค๋ฌ์์ง ์ ์์
๋ ์ข์ ๋ฐฉ๋ฒ : REACT
reactdhk react-dom ์คํฌ๋ฆฝํธ ์ถ๊ฐ ๋จผ์ ํ์.
<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>

<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script>
const root = document.getElementById("root");
const span = React.createElement("span", [content]);
ReactDOM.render(span, root)
</script>
</html>

const root = document.getElementById("root");
const span = React.createElement(
"h3", {
id: "prettyspan",
style: {color: "blue"},
onMouseEnter: () => console.log("mouse enter!")
}, "Hello I'm a span");
const btn = React.createElement(
"button", {
onClick: () => console.log("i'm clicked")
}, "Click me");
const container = React.createElement("div", null, [span, btn]);
ReactDOM.render(container, root)


const span = React.createElement(
"h3", {
id: "prettyspan",
style: {color: "blue"},
onMouseEnter: () => {
count++;
console.log("mouse enter! ");
console.log(count);
}
}, "Hello I'm a span");
const btn = React.createElement(
"button", {
onClick: () => console.log("i'm clicked")
}, "Click me");
const Title = (
<h3 id="title" onMouseEnter={() => console.log("mouse enter!")}>
"Hello I'm a span"
</h3>
);
const Button = (
<button
style={{
backgroundColor: "tomato"
}}
onClick={() => console.log("i'm clicked")}
>
click me!
</button>
);
button element๋ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ง๋ค์ด์ฃผ์๋ค.
์ด๋๋ก live server๋ฅผ ๋๋ฆฌ๋ฉด ์๋ฌ๊ฐ ๋จ๋๋ฐ,


์ฐ๋ฆฌ๋ ์ง๊ธ ๋ฐฐ์ฐ๊ณ ์์ด์ ์ด ๋ฐฉ์์ผ๋ก ์งํํ๋ ๊ฑฐ์ง, ํผ์ํ ๋๋ ์ ๋ ์ด๋ ๊ฒ ํ ์ผ ์์๊ฒ ๋๋ฆฌ๊ธฐ๋๋ฌธ. ๋ ๋์ ๋ฐฉ์์ด ์์

babel์ importํด์ฃผ๊ณ script ์์ type์ ์ง์ ํด์ฃผ๋ฉด ์ด๋ ๊ฒ ์ ๋จ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
function Title() {
return(
<h3 id="title" onMouseEnter={() => console.log("mouse enter!")}>
"Hello I'm a span"
</h3>
);
};
const Button = ()=> (
<button
style={{
backgroundColor: "tomato"
}}
onClick={() => console.log("i'm clicked")}
>
click me!
</button>
);
const Container = (
<div>
<Title />
<Button />
</div>
);
<script type="text/babel">
const root = document.getElementById("root");
let counter = 0;
function countUp(){
counter = counter+1;
}
const Container = () => (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={countUp}> click me!</button>
</div>
);
ReactDOM.render(<Container />, root)
</script>

์ฐ๋ฆฌ๊ฐ countUp ํจ์๊ฐ ์คํ๋ ๋๋ง๋ค render์ ๋ค์ ์คํํด์ฃผ์ด์ผ ํ๋ค.
<script type="text/babel">
const root = document.getElementById("root");
let counter = 0;
function countUp(){
counter = counter+1;
render()
}
function render(){
ReactDOM.render(<Container />, root)
}
const Container = () => (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={countUp}> click me!</button>
</div>
);
render();
</script>
์ด๋ ๊ฒ renderํจ์๋ฅผ ๋ง๋ค์ด์ฃผ๋ฉด ๋งค๋ฒ ui๊ฐ ๋ณ๊ฒฝ๋๋ค.
ํ์ง๋ง ์ด๊ฑด best๊ฐ ์๋๋ค.

<script type="text/babel">
const root = document.getElementById("root");
function Container (){
return (
<div>
<h3>Total clicks: 0</h3>
<button> click me!</button>
</div>
);
}
ReactDOM.render(<Container />, root)
</script>
const [counter, modifier] = React.useState(0);
<script type="text/babel">
const root = document.getElementById("root");
function App (){
const [counter, setCounter] = React.useState(0);
return (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={()=>{setCounter(counter+1)}}> click me!</button>
</div>
);
}
ReactDOM.render(<App />, root)
</script>
setCounter(counter+1);
setCounter((current)=>current+1);
<script type="text/babel">
const root = document.getElementById("root");
function App (){
const [minutes, setMinutes] = React.useState();
const onChange = (event) => {
setMinutes(event.target.value);
}
return (
<div>
<label for="minutes">Minutes</label>
<input value={minutes} id="minutes" placeholder="Minutes" type="number" onChange={onChange}/>
<h4>You want to convert {minutes}</h4>
<label>Hours</label>
<input placeholder="Hours" type="number"/>
</div>
);
}
ReactDOM.render(<App />, root)
</script>

๊ทผ๋ฐ ์ฌ๊ธฐ์ onChange property๋ฅผ ์ง์์ฃผ๋ฉด ์๋ฌด๋ฆฌ ์ ๋ ฅํ๋ ค ํด๋ ๋ํดํธ๊ฐ์ผ๋ก ๊ทธ๋๋ก ๊ณ ์ ๋จ. ๊ทธ๋์ value์ onchange ๋๋ค ํ์
#3.6 State Practice part One
<script type="text/babel">
const root = document.getElementById("root");
function App (){
const [minutes, setMinutes] = React.useState();
const onChange = (event) => {
setMinutes(event.target.value);
}
return (
<div>
<h1>Super Converter</h1>
<label for="minutes">Minutes</label>
<input value={minutes} id="minutes" placeholder="Minutes" type="number" onChange={onChange}/>
<label for="hours">Hours</label>
<input value={minutes/60} placeholder="Hours" type="number" disabled/>
<button onClick={()=>{setMinutes(0)}}>reset</button>
</div>
);
}
ReactDOM.render(<App />, root)
</script>
minute์ hour๋ก ๋ณํ

<script type="text/babel">
const root = document.getElementById("root");
function App (){
const [minutes, setMinutes] = React.useState(0);
const [hours, setHours] = React.useState(0);
const [flipped, setFlipped] = React.useState(false);
const onChange = (event) => {
if(!flipped) {
setMinutes(event.target.value);
setHours(event.target.value/60);
}
else {
setHours(event.target.value);
setMinutes(event.target.value*60);
}
};
const reset = () => {
setMinutes(0);
setHours(0);
};
const onFlip = () => {
setFlipped((current)=> !current);
reset();
};
return (
<div>
<h1>Super Converter</h1>
<label for="minutes">Minutes</label>
<input value={minutes} id="minutes" placeholder="Minutes" type="number" onChange={onChange} disabled ={flipped}/>
<label for="hours">Hours</label>
<input value={hours} id="hours" placeholder="Hours" type="number" onChange={onChange} disabled ={!flipped} />
<button onClick={reset}>reset</button>
<button onClick={onFlip}>flip</button>
</div>
);
}
ReactDOM.render(<App />, root)
</script>
์ด๋ ๊ฒ ํ๋ฉด ๋ฒํผ ๋ user-friendly
<button onClick={onFlip}>{flipped? "๋ถ->์๋ก ๋ฐ๊พธ๊ธฐ" : "์->๋ถ์ผ๋ก ๋ฐ๊พธ๊ธฐ"}</button>
const root = document.getElementById("root");
function MinutesToHours(){
const [minutes, setMinutes] = React.useState(0);
const [hours, setHours] = React.useState(0);
const [flipped, setFlipped] = React.useState(false);
const onChange = (event) => {
if(!flipped) {
setMinutes(event.target.value);
setHours(event.target.value/60);
}
else {
setHours(event.target.value);
setMinutes(event.target.value*60);
}
};
const reset = () => {
setMinutes(0);
setHours(0);
};
const onFlip = () => {
setFlipped((current)=> !current);
reset();
};
return (
<div>
<label for="minutes">Minutes</label>
<input value={minutes} id="minutes" placeholder="Minutes" type="number" onChange={onChange} disabled ={flipped}/>
<label for="hours">Hours</label>
<input value={hours} id="hours" placeholder="Hours" type="number" onChange={onChange} disabled ={!flipped} />
<button onClick={reset}>reset</button>
<button onClick={onFlip}>{flipped? "๋ถ->์๋ก ๋ฐ๊พธ๊ธฐ" : "์->๋ถ์ผ๋ก ๋ฐ๊พธ๊ธฐ"}</button>
</div>
);
};
function KmToMiles(){
const [km, setKm] = React.useState(0);
const [miles, setMiles] = React.useState(0);
const [flipped, setFlipped] = React.useState(false);
const onChange = (event) => {
if(!flipped) {
setKm(event.target.value);
setMiles(event.target.value/1.609344);
}
else {
setMiles(event.target.value);
setKm(event.target.value*1.609344);
}
};
const reset = () => {
setKm(0);
setMiles(0);
};
const onFlip = () => {
setFlipped((current)=> !current);
reset();
};
return (
<div>
<label htmlFor="km">KM</label>
<input value={km} id="km" placeholder="km" type="number" onChange={onChange} disabled ={flipped}/>
<label htmlFor="miles">miles</label>
<input value={miles} id="miles" placeholder="miles" type="number" onChange={onChange} disabled ={!flipped} />
<button onClick={reset}>reset</button>
<button onClick={onFlip}>{flipped? "km->miles๋ก ๋ฐ๊พธ๊ธฐ":"miles->km๋ก ๋ฐ๊พธ๊ธฐ"}</button>
</div>
);
};
function App (){
const [index, setIndex]=React.useState("xx");
function onSelected (event){
setIndex(event.target.value);
}
return (
<div>
<h1>Super Converter</h1>
<select value={index} onChange={onSelected}>
<option value="xx">
Selet
</option>
<option value="0">
Minutes to Hours
</option>
<option value="1">
Km to Miles
</option>
</select>
{index==="0" ? <MinutesToHours /> : null}
{index==="1" ?<KmToMiles /> : null}
</div>
);
};
ReactDOM.render(<App />, root)



const root = document.getElementById("root");
function Btn({bgcolor, text, big}){
return <button style={{
backgroundColor: bgcolor,
color: "tomato",
padding:"10px 20px",
margin: "10px 5px",
border: "1px solid black" ,
borderRadius: 10,
fontSize: big ? 18 : 16
}}> {text} </button>;
}
function App (){
return (
<div>
<Btn text="Save Changes" bgcolor="white" big={true}/>
<Btn text="Continue" bgcolor="black" big={false}/>
</div>
);
}
ReactDOM.render(<App />, root)

const MemorizedBtn = React.memo(Btn);
function App (){
const [value, setValue] = React.useState("Save Changes");
function changeValue(){
setValue("Revert Changes");
}
return (
<div>
<MemorizedBtn text={value} onClick={changeValue} />
<MemorizedBtn text="์๋
" />
</div>
);
}
<script type="text/babel">
const root = document.getElementById("root");
function Btn({text,onClick}){
console.log(text," was rendered");
return <button
onClick={onClick}
style={{
backgroundColor: "black",
color: "tomato",
padding:"10px 20px",
margin: "10px 5px",
border: "1px solid black" ,
borderRadius: 10,
}}
> {text} </button>;
}
const MemorizedBtn = React.memo(Btn);
MemorizedBtn.propTypes={
text: PropTypes.string.isRequired,
onClick: PropTypes.func,
};
function App (){
const [value, setValue] = React.useState("Save Changes");
function changeValue(){
setValue("Revert Changes");
}
return (
<div>
<MemorizedBtn text={value} onClick={changeValue} />
<MemorizedBtn text="์๋
" />
</div>
);
}
ReactDOM.render(<App />, root)
</script>
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// prop๊ฐ ํน์ JS ํ์์์ ์ ์ธํ ์ ์์ต๋๋ค.
// ์ด๊ฒ๋ค์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ์ ํ ์ฌํญ์
๋๋ค.
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// ๋๋๋ง ๋ ์ ์๋ ๊ฒ๋ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
// ์ซ์(numbers), ๋ฌธ์(strings), ์๋ฆฌ๋จผํธ(elements), ๋๋ ์ด๋ฌํ ํ์
๋ค(types)์ ํฌํจํ๊ณ ์๋ ๋ฐฐ์ด(array) (ํน์ ๋ฐฐ์ด์ fragment)
optionalNode: PropTypes.node,
// React ์๋ฆฌ๋จผํธ.
optionalElement: PropTypes.element,
// React ์๋ฆฌ๋จผํธ ํ์
(ie. MyComponent)
optionalElementType: PropTypes.elementType,
// prop๊ฐ ํด๋์ค์ ์ธ์คํด์ค์์ ์ ์ธํ ์ ์์ต๋๋ค.
// ์ด ๊ฒฝ์ฐ JavaScript์ instanceof ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
optionalMessage: PropTypes.instanceOf(Message),
// ์ด๊ฑฐํ(enum)์ผ๋ก ์ฒ๋ฆฌํ์ฌ prop๊ฐ ํน์ ๊ฐ๋ค๋ก ์ ํ๋๋๋ก ํ ์ ์์ต๋๋ค.
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// ์ฌ๋ฌ ์ข
๋ฅ์ค ํ๋์ ์ข
๋ฅ๊ฐ ๋ ์ ์๋ ๊ฐ์ฒด
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// ํน์ ํ์
์ ํ๋ ฌ
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// ํน์ ํ์
์ ํ๋กํผํฐ ๊ฐ๋ค์ ๊ฐ๋ ๊ฐ์ฒด
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// ํน์ ํํ๋ฅผ ๊ฐ๋ ๊ฐ์ฒด
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// ์ถ๊ฐ ํ๋กํผํฐ์ ๋ํ ๊ฒฝ๊ณ ๊ฐ ์๋ ๊ฐ์ฒด
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// ์์ ์๋ ๊ฒ ๋ชจ๋ `isRequired`์ ์ฐ๊ฒฐํ์ฌ prop๊ฐ ์ ๊ณต๋์ง ์์์ ๋
// ๊ฒฝ๊ณ ๊ฐ ๋ณด์ด๋๋ก ํ ์ ์์ต๋๋ค.
requiredFunc: PropTypes.func.isRequired,
// ๋ชจ๋ ๋ฐ์ดํฐ ํ์
์ด ๊ฐ๋ฅํ ํ์๊ฐ
requiredAny: PropTypes.any.isRequired,
// ์ฌ์ฉ์ ์ ์ ์ ํจ์ฑ ๊ฒ์ฌ๊ธฐ๋ฅผ ์ง์ ํ ์๋ ์์ต๋๋ค.
// ๊ฒ์ฌ ์คํจ ์์๋ ์๋ฌ(Error) ๊ฐ์ฒด๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค.
// `oneOfType`์์์๋ ์๋ํ์ง ์์ผ๋ฏ๋ก `console.warn` ํน์ throw ํ์ง ๋ง์ธ์.
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// `arrayOf` ์ `objectOf ์ ์ฌ์ฉ์ ์ ์ ์ ํจ์ฑ ๊ฒ์ฌ๊ธฐ๋ฅผ ์ ์ฉํ ์ ์์ต๋๋ค.
// ๊ฒ์ฌ ์คํจ ์์๋ ์๋ฌ(Error) ๊ฐ์ฒด๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค.
// ์ ํจ์ฑ ๊ฒ์ฌ๊ธฐ๋ ๋ฐฐ์ด(array) ํน์ ๊ฐ์ฒด์ ๊ฐ ํค(key)์ ๋ํ์ฌ ํธ์ถ๋ ๊ฒ์
๋๋ค.
// ์ ํจ์ฑ ๊ฒ์ฌ๊ธฐ์ ์ฒซ ๋ ๊ฐ์ ๋ณ์๋ ๋ฐฐ์ด ํน์ ๊ฐ์ฒด ์์ ๊ณผ ํ์ฌ ์์ดํ
์ ํค์
๋๋ค.
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};
Button.js
import PropTypes from "prop-types";
import style from "./Button.module.css"
function Button({text}){
return (
<button className={style.btn}>{text}</button>
);
}
Button.propTypes = {
text : PropTypes.string.isRequired,
};
export default Button;

.title{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 18px;
}โ
Dependency
import {useState, useEffect} from "react";
function App() {
const [counter, setValue] = useState(0);
const [keyword, setKeyword] = useState("");
const onClick = () => setValue((prev)=>prev+1);
const onChange = (event) => setKeyword(event.target.value);
console.log("I run all the time");
useEffect(()=>{
console.log("CALL the API...");
}, []);
useEffect(()=>{
console.log("Search for", keyword);
}, [keyword]);
return (
<div>
<input
value={keyword}
onChange={onChange}
type="text"
placeholder="Search here..."
/>
<h1> {counter} </h1>
<button onClick={onClick} >click</button>
</div>
);
}
export default App;

useEffect(()=>{
if(keyword.length>5)
console.log("Search for", keyword);
}, [keyword]);
์ด๋ ๊ฒ ์กฐ๊ฑด๋ ์ถ๊ฐํ ์ ์๋ค.

[] ์ด ์์ ๊ฒ์ ๋ฆฌ์กํธ๊ฐ ์ง์ผ๋ณด๊ณ ์๋ค๊ณ ์๊ฐํ๋ฉด ์ฝ๋ค. ์๋ฌด๊ฒ๋ ์๋ ๊ฑด ์ง์ผ๋ด๋ ์๋ฌด์ผ์ด ์์ผ๋๊น ์ฒ์ ์คํ๋ ๋๋ง ์ฝ์๋ก๊ทธ๊ฐ ์๋ํ๋ ๊ฒ์ด๋ค. ๋ฆฌ์คํธ์ด๊ธฐ ๋๋ฌธ์ [counter, keyword] ์ด๋ ๊ฒ ๋ฃ์ด๋ ๋๋ค. ๋ ์ค ํ๋๊ฐ ์คํ๋ ๋ ์ฝ๋๊ฐ ์๋ํ๋ค.
import {useState, useEffect} from "react";
function Hello(){
useEffect(()=>{
console.log("I'm here :)");
return () => console.log("destroyed :(")
},[]);
return <h1>Hello</h1>
}
function App() {
const [showing, setShowing] = useState(false);
const onClick = () => setShowing((prev)=>!prev);
return (
<div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing?"hide":"show"}</button>
</div>
);
}
export default App;

import {useState, useEffect} from "react";
function Hello(){
function effectFn(){
console.log("created :)");
return byeFn
}
function byeFn(){
console.log("bye~ .. ")
}
useEffect(effectFn,[]);
return <h1>Hello</h1>
}
function App() {
const [showing, setShowing] = useState(false);
const onClick = () => setShowing((prev)=>!prev);
return (
<div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing?"hide":"show"}</button>
</div>
);
}
export default App;
import { useState } from "react";
function App() {
const [toDo, setToDo] = useState("");
const [toDos, setToDos] = useState([]);
const onChange = (event) => setToDo(event.target.value);
const onSubmit = (event) => {
event.preventDefault();
if (toDo === "") {
return;
}
setToDos((currentArray) => [toDo, ...currentArray]);
setToDo("");
};
return (
<div>
<h1>My To Dos ({toDos.length})</h1>
<form onSubmit={onSubmit}>
<input
onChange={onChange}
value={toDo}
type="text"
placeholder="Write your to do..."
/>
<button>Add To Do</button>
</form>
</div>
);
}
export default App;
setToDos((currentArray) => [toDo, ...currentArray]);
setToDo("");
import { useState } from "react";
function App() {
const [toDo, setToDo] = useState("");
const [toDos, setToDos] = useState([]);
const onChange = (event) => setToDo(event.target.value);
const onSubmit = (event) => {
event.preventDefault();
if (toDo === "") {
return;
}
setToDos((currentArray) => [toDo, ...currentArray]);
setToDo("");
};
return (
<div>
<h1>My To Dos ({toDos.length})</h1>
<form onSubmit={onSubmit}>
<input
onChange={onChange}
value={toDo}
type="text"
placeholder="Write your to do..."
/>
<button>Add To Do</button>
</form>
<hr />
{toDos.map((item, index)=>
<li key={index}>{item}</li>
)}
</div>
);
}
export default App;

import { useState, useEffect } from "react";
function App() {
const [loading, setLoading]= useState(true);
const [coins, setCoins] = useState([])
useEffect(() => {
fetch("http://api.coinpaprika.com/v1/tickers")
.then((response) => response.json())
.then((json) => {
setCoins(json);
setLoading(false);
});
}, []);
return (
<div>
<h1>The Coins!({coins.length})</h1>
{loading ? <strong>Loading...</strong>:
<ul>
{coins.map((coin)=> (
<li>
{coin.name} ({coin.symbol}): ({coin.quotes.USD.price}) USD
</li>
))}
</ul>
}
</div>
);
}
export default App;โ
import { useState, useEffect } from "react";
function App() {
const [coins, setCoins] = useState([])
const [input, setInput] = useState(0);
const [selected, setSelected] = useState(0);
function onChanged(event){
setInput(event.target.value);
console.log(input);
}
function onSelected(event){
setSelected(event.target.value);
console.log(selected);
}
useEffect(() => {
fetch("http://api.coinpaprika.com/v1/tickers")
.then((response) => response.json())
.then((json) => {
setCoins(json);
});
}, []);
return (
<div>
<h1>The Coins!({coins.length})</h1>
<form>
<input value={input} onChange={onChanged} type="number" placeholder="input money"></input>
</form>
{input!==0 ?
<div>
<select value={selected} onChange={onSelected}>
{coins.map((coin, index)=> (
<option key={index} value={coin.quotes.USD.price}>
{coin.name} ({coin.symbol}): ({coin.quotes.USD.price}) USD
</option>
))}
</select>
<h1>{input/selected}</h1>
</div>
: null
}
</div>
);
}
export default App;
import { useState, useEffect } from "react";
function App() {
const [movies, setMovies] = useState([])
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year")
.then((response) => response.json())
.then((json) => {
console.log(json);
});
}, []);
return (
<div>
{loading ? <h1>Loading...</h1> : null}
</div>
);
}
export default App;

useEffect(() => {
fetch("https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year")
.then((response) => response.json())
.then((json) => {
setMovies(json.data.movies);
console.log(movies);
setLoading((cur)=>!cur);
});
}, []);

import { useState, useEffect } from "react";
function App() {
const [movies, setMovies] = useState([])
const [loading, setLoading] = useState(true);
const getMovies = async() => {
const json = await(await fetch("https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year")).json();
setMovies(json.data.movies);
setLoading(false);
}
useEffect(() => {
getMovies();
}, []);
return (
<div>
{loading ? <h1>Loading...</h1> : null}
</div>
);
}
export default App;
import { useState, useEffect } from "react";
function App() {
const [movies, setMovies] = useState([])
const [loading, setLoading] = useState(true);
const getMovies = async() => {
const json = await(await fetch("https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year")).json();
setMovies(json.data.movies);
setLoading(false);
}
useEffect(() => {
getMovies();
}, []);
console.log(movies);
return (
<div>
{loading
? <h1>Loading...</h1>
: <div>
{movies.map(movie=>
<div key={movie.id}>
<img src={movie.medium_cover_image}></img>
<h2>{movie.title}</h2>
<p>{movie.summary}</p>
<ul>
{movie.genres.map((g)=>
<li key={g}>{g}</li>)}
</ul>
</div>
)}
</div>
}
</div>
);
}
export default App;โ
import { useState, useEffect } from "react";
import Movie from "./Movie";
function App() {
const [movies, setMovies] = useState([])
const [loading, setLoading] = useState(true);
const getMovies = async() => {
const json = await(await fetch("https://yts.mx/api/v2/list_movies.json?minimum_rating=8.8&sort_by=year")).json();
setMovies(json.data.movies);
setLoading(false);
}
useEffect(() => {
getMovies();
}, []);
console.log(movies);
return (
<div>
{loading ? <h1>Loading...</h1>
: <div>
{movies.map(movie=>
<Movie
key={movie.id}
coverImg={movie.medium_cover_image}
title={movie.title}
summary={movie.summary}
genres={movie.genres}
/>
)}
</div>
}
</div>
);
}
export default App;
import PropTypes from "prop-types";
function Movie({ coverImg, title, summary, genres}){
return(
<div>
<img src={coverImg} alt={title}></img>
<h2>{title}</h2>
<p>{summary}</p>
<ul>
{genres.map((g)=>
<li key={g}>{g}</li>)}
</ul>
</div>
);
}
Movie.propTypes={
coverImg: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
summary: PropTypes.string.isRequired,
genres: PropTypes.arrayOf(PropTypes.string).isRequired
};
export default Movie;
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
import Home from "./routes/Home";
import Detail from "./routes/Detail";
function App() {
return <Router>
<Switch>
<Route path="/movie">
<Detail />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>;
}
export default App;
import {
BrowserRouter as Router,
Route,
Routes,
} from "react-router-dom";
import HomePage from "./routes/HomePage";
import AboutPage from "./routes/AboutPage";
function App() {
return <Router>
<Routes>
<Route path="/" element={<HomePage />}>
</Route>
<Route path="/about" element={<AboutPage />}>
</Route>
</Routes>
</Router>;
}
export default App;

import PropTypes from "prop-types";
import {Link} from "react-router-dom";
function Movie({coverImg, title, summary, genres}){
return(
<div>
<img src={coverImg} alt={title}></img>
<h2>
<Link to="/movie">{title}</Link>
</h2>
<p>{summary}</p>
<ul>
{genres.map((g)=>
<li key={g}>{g}</li>)}
</ul>
</div>
);
}
<Link to={`/movie/${id}`}>{title}</Link>

<Route path="/movie/:id">
<Detail />
</Route>
GitHub - chamroro/ReactMovieService
Contribute to chamroro/ReactMovieService development by creating an account on GitHub.
github.com
]
},
"homepage":"https://chamroro.github.io/ReactMovieService"
}
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"deploy": "gh-pages -d build",
"predeploy": "npm run build"
},
์์ ๊ฐ์ด ์ถ๊ฐํ๋ฉด build ํด๋๋ฅผ ์ญ์ ํ๊ณ npm run deploy์ด๋ ๊ฒ ํ๋ฉด predeploy ๊ฐ ๋ ํ์ buld๋ฅผ ํ๋ค.



React App
chamroro.github.io