react.js
応答はJavaScriptから始まり、htmlです.
JSXはJavaScriptを拡張する文法です.
props == propertys
構成部品の最初の文字は大文字でなければなりません.
反応の利点は,UIで変更された部分のみを更新することである.
構成部品を作成する方法.
1) function a() {
return()
}
2) const b = () => ();state
そしてpackagejsonに入り、 を以下のように記述する
predeployを作成する理由は、構築と導入が必要であることを知りたくないからです.
したがって、deploy、nodeを実行すると.jsはまずpredeployを実行する
その後、導入を開始します.
breaking changes
JSXはJavaScriptを拡張する文法です.
props == propertys
構成部品の最初の文字は大文字でなければなりません.
反応の利点は,UIで変更された部分のみを更新することである.
構成部品を作成する方法.
1) function a() {
return()
}
2) const b = () => ();
<!DOCTYPE html>
<html lang="en">
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const root = document.getElementById('root');
function Title() {
return (
<h3 id="title" onMouseEnter={() => console.log('mouse enter')}>
Hello I'm a title
</h3>
);
}
// 소괄호는 return 한다는 걸 전제.
const Button = () => (
<button
style={{
backgroundColor: 'tomato',
}}
onClick={() => console.log('im clicked')}
>
Click me
</button>
);
const Container = () => (
<div>
<Title />
<Button />
</div>
);
ReactDOM.render(<Container />, root);
</script>
</html>
state
デフォルトでは、データはどこに格納されますか.const root = document.getElementById('root');
function App() {
// setcounter는 실행되면 새값을 가지고 다시 렌더링 함.
const [counter, setCounter] = React.useState(0);
const onClick = () => {
//setCounter(counter + 1);
setCounter((current) => current + 1);
};
return (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={onClick}>Click me</button>
</div>
);
}
ReactDOM.render(<App />, root);
pratice
converter<!DOCTYPE html>
<html lang="en">
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function MinutesToHours() {
const [amount, setAmount] = React.useState(0);
const [inverted, setInverted] = React.useState(false);
const onChange = (event) => {
setAmount(event.target.value);
};
const reset = () => setAmount(0);
const onFlip = () => {
reset();
setInverted((current) => !current);
};
return (
<div>
<div>
<label htmlFor="minutes">Minutes</label>
<input
value={inverted ? amount * 60 : amount}
id="minutes"
placeholder="Minutes"
type="number"
onChange={onChange}
disabled={inverted}
/>
</div>
<div>
<label htmlFor="hours">Hours</label>
<input
value={inverted ? amount : Math.round(amount / 60)}
id="hours"
placeholder="Hours"
type="number"
disabled={!inverted}
onChange={onChange}
/>
</div>
<button onClick={reset}>Reset</button>
<button onClick={onFlip}>{inverted ? 'Turn back' : 'Invert'}</button>
</div>
);
}
function KmToMiles() {
const [amount, setAmount] = React.useState(1);
const [inverted, setInverted] = React.useState(false);
const onChange = (event) => {
setAmount(event.target.value);
};
const reset = () => setAmount(1);
const onFlip = () => {
reset();
setInverted((current) => !current);
};
return (
<div>
<div>
<label htmlFor="km">Km</label>
<input
value={inverted ? amount * 1.609 : amount}
id="km"
placeholder="Km"
type="number"
onChange={onChange}
disabled={inverted}
/>
</div>
<div>
<label htmlFor="miles">Miles</label>
<input
value={inverted ? amount : (amount / 1.609).toFixed(4)}
id="miles"
placeholder="Miles"
type="number"
disabled={!inverted}
onChange={onChange}
/>
</div>
<button onClick={reset}>Reset</button>
<button onClick={onFlip}>{inverted ? 'Turn back' : 'Invert'}</button>
</div>
);
}
function App() {
const [index, setIndex] = React.useState('xx');
const onSelect = (event) => {
setIndex(event.target.value);
};
return (
<div>
<h1>Super Converter</h1>
<select value={index} onChange={onSelect}>
<option value="xx">Selct your units</option>
<option value="0">Minutes & Hours</option>
<option value="1">KM & Miles</option>
</select>
<hr />
{index === 'xx' ? 'Please select your units' : null}
{index === '0' ? <MinutesToHours /> : null}
{index === '1' ? <KmToMiles /> : null}
</div>
);
}
const root = document.getElementById('root');
ReactDOM.render(<App />, root);
</script>
</html>
props
親構成部品から子構成部品にデータを送信する方法.
構成部品はjsxを返す関数です.
React.jsは、関数内のすべてのアイテムを自動的にオブジェクトに入れます.
このオブジェクトは、構成部品の最初のパラメータであり、唯一のパラメータでもあります(2番目のパラメータはありません).
ex).<Btn banana="Save Changes">
// => Btn({banana:"Save Changes"})
function Btn({ banana, big }) {
return (
<button
style={{
backgroundColor: 'tomato',
color: 'white',
padding: '10px 20px',
border: 0,
borderRadius: 10,
fontSize: big ? 18 : 16,
}}
>
{banana}
</button>
);
}
function App() {
return (
<div>
<Btn banana="Save Changes" big={true} />
<Btn banana="Continue" big={false} />
</div>
);
}
const root = document.getElementById('root');
ReactDOM.render(<App />, root);
memo
構成部品をレンダリングするかどうかを決定できます.function Btn({ text, onClick }) {
console.log(text, 'was rendered');
return (
<button
onClick={onClick}
style={{
backgroundColor: 'tomato',
color: 'white',
padding: '10px 20px',
border: 0,
borderRadius: 10,
}}
>
{text}
</button>
);
}
// state가 변하면 함수는 re render함.
// prop가 변하지 않을때도 컴포넌트가 리 렌더링 될 때가 있음.
// 원하질 않을 경우 memo를 사용.
// 그러면 props가 변할때는 컴포넌트가 변하고 props가 변하지 않을때는 컴포넌트가 리 렌더링 되지 않음.
const MemorizedBtn = React.memo(Btn);
function App() {
const [value, setValue] = React.useState('Save Changes');
const changeValue = () => setValue('Revert Changes');
// 여기서 onClick은 이벤트 리스너가 아니고 prop의 이름
// 왜냐하면 html 요소에 넣는게 아니라 컴포넌트에 넣는거니까.
// 커스텀 컴포넌트에 변수이름에 뭐든지 사용해도 상관없음.
return (
<div>
<MemorizedBtn text={value} onClick={changeValue} />
<MemorizedBtn text="Continue" />
</div>
);
}
const root = document.getElementById('root');
ReactDOM.render(<App />, root);
prop types
どんな種類の道具かチェックしてくださいfunction Btn({ text, fontSize = 16 }) {
console.log(text, 'was rendered');
return (
<button
style={{
backgroundColor: 'tomato',
color: 'white',
padding: '10px 20px',
border: 0,
borderRadius: 10,
fontSize,
}}
>
{text}
</button>
);
}
Btn.propTypes = {
text: PropTypes.string.isRequired,
fontSize: PropTypes.number,
};
function App() {
const [value, setValue] = React.useState('Save Changes');
const changeValue = () => setValue('Revert Changes');
// 여기서 onClick은 이벤트 리스너가 아니고 prop의 이름
// 왜냐하면 html 요소에 넣는게 아니라 컴포넌트에 넣는거니까.
// 커스텀 컴포넌트에 변수이름에 뭐든지 사용해도 상관없음.
return (
<div>
<Btn text={value} fontSize={18} />
<Btn text={value} />
</div>
);
}
create-react-app
応答アプリケーションの作成に最適です.
npmx create-act-appプロジェクト名
MODULE.CSS
:CRA固有の機能としてclassNameを使用して、非グローバル構成部品のスタイルを指定できます.
useEffect
コードを最初のプレゼンテーションでのみ実行し、他のステータスが変化したときに実行しないようにします.
例)APIを使用してデータを入力すると、構成部品レンダリングによってAPIが呼び出されます.
以降状態が変化した場合には、APIからのデータの再取得を避けることができる
useEffect(callback, [])
:一般的な使用法=>APIは1回のみ呼び出され、これ以上呼び出されたくない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);
};
// 한번만 렌더링 되고 실행안됨.
// 아무것도 보고 있지 않기 때문에.
useEffect(() => {
console.log('i run only once.');
}, []);
// keyword가 변할때만 다시 렌더링
useEffect(() => {
console.log("I run when 'keyword' changes.");
}, [keyword]);
// counter가 변할때만 다시 렌더링
useEffect(() => {
console.log("I run when 'counter' changes.");
}, [counter]);
// keyword 또는 counter가 변할때 다시 렌더링
useEffect(() => {
console.log('I run when keyword & counter change.');
}, [keyword, counter]);
return (
<div>
<input
value={keyword}
onChange={onChange}
type="text"
placeholder="Search here...."
/>
<h1>{counter}</h1>
<button onClick={onClick}>Click me</button>
</div>
);
}
export default App;
cleanup function import { useState, useEffect } from 'react';
function Hello() {
useEffect(() => {
console.log('created :)');
//cleanup function(컴포넌트가 destroy될때 사용)
//ex.컴포넌트가 없어질때 어떤 분석 결과를 보내고 싶을때,
//또는 eventlistener를 지우고 싶을때
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;
react-router-dom import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Detail from './routes/Detail';
import Home from './routes/Home';
function App() {
//switch는 route를 찾아서 컴포넌트를 렌더링 .
//한번에 하나의 route만 렌더링 하기 위해서 switch 씀.
return (
<Router>
<Switch>
<Route path="/movie/:id">
<Detail />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
export default App;
import PropTypes from 'prop-types';
//Link는 브라우저 새로고침 없이도 유저를 다른 페이지로 이동 시켜주는 컴포넌트.
import { Link } from 'react-router-dom';
import styles from './Movie.module.css';
function Movie({ id, coverImg, title, year, summary, genres }) {
return (
<div className={styles.movie}>
<img className={styles.movie__img} src={coverImg} alt={title} />
<div>
<h2 className={styles.movie__title}>
<Link to={`/movie/${id}`}>{title}</Link>
</h2>
<h3 className={styles.movie__year}>{year}</h3>
<p>{summary.length > 235 ? `${summary.slice(0, 235)}...` : summary}</p>
<ul className={styles.movie__genres}>
{genres.map((g, index) => (
<li key={index}>{g}</li>
))}
</ul>
</div>
</div>
);
}
Movie.propTypes = {
id: PropTypes.number.isRequired,
coverImg: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
summary: PropTypes.string.isRequired,
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
};
export default Movie;
parameter //useparams는 react router의 변수 값을 넘겨줌.
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import styles from './Detail.module.css';
function Detail() {
const [loading, setLoading] = useState(true);
const [movie, setMovie] = useState([]);
const { id } = useParams();
const getMovie = useCallback(async () => {
const json = await (
await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
).json();
setMovie(json.data.movie);
setLoading(false);
}, [id]);
useEffect(() => {
getMovie();
}, [getMovie]);
return (
<div className={styles.loader}>
{loading ? (
<h1>Loading...</h1>
) : (
<div className={styles.movie}>
<img
className={styles.img}
src={movie.medium_cover_image}
alt={movie.title}
/>
<div>
<h1>{movie.title}</h1>
<p>{movie.description_intro}</p>
<p>language: {movie.language}</p>
<p>Rating: {movie.rating}</p>
<p>Year: {movie.year}</p>
</div>
</div>
)}
</div>
);
}
export default Detail;
ダウンジャケットページ配布
npm i gh-pages
1.npm run buildを実行すると、Webサイトの本番準備コードが生成されます.
production readyとは,コードが圧縮され,すべてが最適化されることである.
実行するとbuildというフォルダが作成されます
const root = document.getElementById('root');
function App() {
// setcounter는 실행되면 새값을 가지고 다시 렌더링 함.
const [counter, setCounter] = React.useState(0);
const onClick = () => {
//setCounter(counter + 1);
setCounter((current) => current + 1);
};
return (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={onClick}>Click me</button>
</div>
);
}
ReactDOM.render(<App />, root);
<!DOCTYPE html>
<html lang="en">
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function MinutesToHours() {
const [amount, setAmount] = React.useState(0);
const [inverted, setInverted] = React.useState(false);
const onChange = (event) => {
setAmount(event.target.value);
};
const reset = () => setAmount(0);
const onFlip = () => {
reset();
setInverted((current) => !current);
};
return (
<div>
<div>
<label htmlFor="minutes">Minutes</label>
<input
value={inverted ? amount * 60 : amount}
id="minutes"
placeholder="Minutes"
type="number"
onChange={onChange}
disabled={inverted}
/>
</div>
<div>
<label htmlFor="hours">Hours</label>
<input
value={inverted ? amount : Math.round(amount / 60)}
id="hours"
placeholder="Hours"
type="number"
disabled={!inverted}
onChange={onChange}
/>
</div>
<button onClick={reset}>Reset</button>
<button onClick={onFlip}>{inverted ? 'Turn back' : 'Invert'}</button>
</div>
);
}
function KmToMiles() {
const [amount, setAmount] = React.useState(1);
const [inverted, setInverted] = React.useState(false);
const onChange = (event) => {
setAmount(event.target.value);
};
const reset = () => setAmount(1);
const onFlip = () => {
reset();
setInverted((current) => !current);
};
return (
<div>
<div>
<label htmlFor="km">Km</label>
<input
value={inverted ? amount * 1.609 : amount}
id="km"
placeholder="Km"
type="number"
onChange={onChange}
disabled={inverted}
/>
</div>
<div>
<label htmlFor="miles">Miles</label>
<input
value={inverted ? amount : (amount / 1.609).toFixed(4)}
id="miles"
placeholder="Miles"
type="number"
disabled={!inverted}
onChange={onChange}
/>
</div>
<button onClick={reset}>Reset</button>
<button onClick={onFlip}>{inverted ? 'Turn back' : 'Invert'}</button>
</div>
);
}
function App() {
const [index, setIndex] = React.useState('xx');
const onSelect = (event) => {
setIndex(event.target.value);
};
return (
<div>
<h1>Super Converter</h1>
<select value={index} onChange={onSelect}>
<option value="xx">Selct your units</option>
<option value="0">Minutes & Hours</option>
<option value="1">KM & Miles</option>
</select>
<hr />
{index === 'xx' ? 'Please select your units' : null}
{index === '0' ? <MinutesToHours /> : null}
{index === '1' ? <KmToMiles /> : null}
</div>
);
}
const root = document.getElementById('root');
ReactDOM.render(<App />, root);
</script>
</html>
親構成部品から子構成部品にデータを送信する方法.
構成部品はjsxを返す関数です.
React.jsは、関数内のすべてのアイテムを自動的にオブジェクトに入れます.
このオブジェクトは、構成部品の最初のパラメータであり、唯一のパラメータでもあります(2番目のパラメータはありません).
ex).
<Btn banana="Save Changes">
// => Btn({banana:"Save Changes"})
function Btn({ banana, big }) {
return (
<button
style={{
backgroundColor: 'tomato',
color: 'white',
padding: '10px 20px',
border: 0,
borderRadius: 10,
fontSize: big ? 18 : 16,
}}
>
{banana}
</button>
);
}
function App() {
return (
<div>
<Btn banana="Save Changes" big={true} />
<Btn banana="Continue" big={false} />
</div>
);
}
const root = document.getElementById('root');
ReactDOM.render(<App />, root);
memo
構成部品をレンダリングするかどうかを決定できます.function Btn({ text, onClick }) {
console.log(text, 'was rendered');
return (
<button
onClick={onClick}
style={{
backgroundColor: 'tomato',
color: 'white',
padding: '10px 20px',
border: 0,
borderRadius: 10,
}}
>
{text}
</button>
);
}
// state가 변하면 함수는 re render함.
// prop가 변하지 않을때도 컴포넌트가 리 렌더링 될 때가 있음.
// 원하질 않을 경우 memo를 사용.
// 그러면 props가 변할때는 컴포넌트가 변하고 props가 변하지 않을때는 컴포넌트가 리 렌더링 되지 않음.
const MemorizedBtn = React.memo(Btn);
function App() {
const [value, setValue] = React.useState('Save Changes');
const changeValue = () => setValue('Revert Changes');
// 여기서 onClick은 이벤트 리스너가 아니고 prop의 이름
// 왜냐하면 html 요소에 넣는게 아니라 컴포넌트에 넣는거니까.
// 커스텀 컴포넌트에 변수이름에 뭐든지 사용해도 상관없음.
return (
<div>
<MemorizedBtn text={value} onClick={changeValue} />
<MemorizedBtn text="Continue" />
</div>
);
}
const root = document.getElementById('root');
ReactDOM.render(<App />, root);
prop types
どんな種類の道具かチェックしてくださいfunction Btn({ text, fontSize = 16 }) {
console.log(text, 'was rendered');
return (
<button
style={{
backgroundColor: 'tomato',
color: 'white',
padding: '10px 20px',
border: 0,
borderRadius: 10,
fontSize,
}}
>
{text}
</button>
);
}
Btn.propTypes = {
text: PropTypes.string.isRequired,
fontSize: PropTypes.number,
};
function App() {
const [value, setValue] = React.useState('Save Changes');
const changeValue = () => setValue('Revert Changes');
// 여기서 onClick은 이벤트 리스너가 아니고 prop의 이름
// 왜냐하면 html 요소에 넣는게 아니라 컴포넌트에 넣는거니까.
// 커스텀 컴포넌트에 변수이름에 뭐든지 사용해도 상관없음.
return (
<div>
<Btn text={value} fontSize={18} />
<Btn text={value} />
</div>
);
}
create-react-app
応答アプリケーションの作成に最適です.
npmx create-act-appプロジェクト名
MODULE.CSS
:CRA固有の機能としてclassNameを使用して、非グローバル構成部品のスタイルを指定できます.
useEffect
コードを最初のプレゼンテーションでのみ実行し、他のステータスが変化したときに実行しないようにします.
例)APIを使用してデータを入力すると、構成部品レンダリングによってAPIが呼び出されます.
以降状態が変化した場合には、APIからのデータの再取得を避けることができる
useEffect(callback, [])
:一般的な使用法=>APIは1回のみ呼び出され、これ以上呼び出されたくない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);
};
// 한번만 렌더링 되고 실행안됨.
// 아무것도 보고 있지 않기 때문에.
useEffect(() => {
console.log('i run only once.');
}, []);
// keyword가 변할때만 다시 렌더링
useEffect(() => {
console.log("I run when 'keyword' changes.");
}, [keyword]);
// counter가 변할때만 다시 렌더링
useEffect(() => {
console.log("I run when 'counter' changes.");
}, [counter]);
// keyword 또는 counter가 변할때 다시 렌더링
useEffect(() => {
console.log('I run when keyword & counter change.');
}, [keyword, counter]);
return (
<div>
<input
value={keyword}
onChange={onChange}
type="text"
placeholder="Search here...."
/>
<h1>{counter}</h1>
<button onClick={onClick}>Click me</button>
</div>
);
}
export default App;
cleanup function import { useState, useEffect } from 'react';
function Hello() {
useEffect(() => {
console.log('created :)');
//cleanup function(컴포넌트가 destroy될때 사용)
//ex.컴포넌트가 없어질때 어떤 분석 결과를 보내고 싶을때,
//또는 eventlistener를 지우고 싶을때
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;
react-router-dom import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Detail from './routes/Detail';
import Home from './routes/Home';
function App() {
//switch는 route를 찾아서 컴포넌트를 렌더링 .
//한번에 하나의 route만 렌더링 하기 위해서 switch 씀.
return (
<Router>
<Switch>
<Route path="/movie/:id">
<Detail />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
export default App;
import PropTypes from 'prop-types';
//Link는 브라우저 새로고침 없이도 유저를 다른 페이지로 이동 시켜주는 컴포넌트.
import { Link } from 'react-router-dom';
import styles from './Movie.module.css';
function Movie({ id, coverImg, title, year, summary, genres }) {
return (
<div className={styles.movie}>
<img className={styles.movie__img} src={coverImg} alt={title} />
<div>
<h2 className={styles.movie__title}>
<Link to={`/movie/${id}`}>{title}</Link>
</h2>
<h3 className={styles.movie__year}>{year}</h3>
<p>{summary.length > 235 ? `${summary.slice(0, 235)}...` : summary}</p>
<ul className={styles.movie__genres}>
{genres.map((g, index) => (
<li key={index}>{g}</li>
))}
</ul>
</div>
</div>
);
}
Movie.propTypes = {
id: PropTypes.number.isRequired,
coverImg: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
summary: PropTypes.string.isRequired,
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
};
export default Movie;
parameter //useparams는 react router의 변수 값을 넘겨줌.
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import styles from './Detail.module.css';
function Detail() {
const [loading, setLoading] = useState(true);
const [movie, setMovie] = useState([]);
const { id } = useParams();
const getMovie = useCallback(async () => {
const json = await (
await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
).json();
setMovie(json.data.movie);
setLoading(false);
}, [id]);
useEffect(() => {
getMovie();
}, [getMovie]);
return (
<div className={styles.loader}>
{loading ? (
<h1>Loading...</h1>
) : (
<div className={styles.movie}>
<img
className={styles.img}
src={movie.medium_cover_image}
alt={movie.title}
/>
<div>
<h1>{movie.title}</h1>
<p>{movie.description_intro}</p>
<p>language: {movie.language}</p>
<p>Rating: {movie.rating}</p>
<p>Year: {movie.year}</p>
</div>
</div>
)}
</div>
);
}
export default Detail;
ダウンジャケットページ配布
npm i gh-pages
1.npm run buildを実行すると、Webサイトの本番準備コードが生成されます.
production readyとは,コードが圧縮され,すべてが最適化されることである.
実行するとbuildというフォルダが作成されます
function Btn({ text, onClick }) {
console.log(text, 'was rendered');
return (
<button
onClick={onClick}
style={{
backgroundColor: 'tomato',
color: 'white',
padding: '10px 20px',
border: 0,
borderRadius: 10,
}}
>
{text}
</button>
);
}
// state가 변하면 함수는 re render함.
// prop가 변하지 않을때도 컴포넌트가 리 렌더링 될 때가 있음.
// 원하질 않을 경우 memo를 사용.
// 그러면 props가 변할때는 컴포넌트가 변하고 props가 변하지 않을때는 컴포넌트가 리 렌더링 되지 않음.
const MemorizedBtn = React.memo(Btn);
function App() {
const [value, setValue] = React.useState('Save Changes');
const changeValue = () => setValue('Revert Changes');
// 여기서 onClick은 이벤트 리스너가 아니고 prop의 이름
// 왜냐하면 html 요소에 넣는게 아니라 컴포넌트에 넣는거니까.
// 커스텀 컴포넌트에 변수이름에 뭐든지 사용해도 상관없음.
return (
<div>
<MemorizedBtn text={value} onClick={changeValue} />
<MemorizedBtn text="Continue" />
</div>
);
}
const root = document.getElementById('root');
ReactDOM.render(<App />, root);
どんな種類の道具かチェックしてください
function Btn({ text, fontSize = 16 }) {
console.log(text, 'was rendered');
return (
<button
style={{
backgroundColor: 'tomato',
color: 'white',
padding: '10px 20px',
border: 0,
borderRadius: 10,
fontSize,
}}
>
{text}
</button>
);
}
Btn.propTypes = {
text: PropTypes.string.isRequired,
fontSize: PropTypes.number,
};
function App() {
const [value, setValue] = React.useState('Save Changes');
const changeValue = () => setValue('Revert Changes');
// 여기서 onClick은 이벤트 리스너가 아니고 prop의 이름
// 왜냐하면 html 요소에 넣는게 아니라 컴포넌트에 넣는거니까.
// 커스텀 컴포넌트에 변수이름에 뭐든지 사용해도 상관없음.
return (
<div>
<Btn text={value} fontSize={18} />
<Btn text={value} />
</div>
);
}
create-react-app
応答アプリケーションの作成に最適です.
npmx create-act-appプロジェクト名
MODULE.CSS
:CRA固有の機能としてclassNameを使用して、非グローバル構成部品のスタイルを指定できます.
useEffect
コードを最初のプレゼンテーションでのみ実行し、他のステータスが変化したときに実行しないようにします.
例)APIを使用してデータを入力すると、構成部品レンダリングによってAPIが呼び出されます.
以降状態が変化した場合には、APIからのデータの再取得を避けることができる
useEffect(callback, [])
:一般的な使用法=>APIは1回のみ呼び出され、これ以上呼び出されたくない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);
};
// 한번만 렌더링 되고 실행안됨.
// 아무것도 보고 있지 않기 때문에.
useEffect(() => {
console.log('i run only once.');
}, []);
// keyword가 변할때만 다시 렌더링
useEffect(() => {
console.log("I run when 'keyword' changes.");
}, [keyword]);
// counter가 변할때만 다시 렌더링
useEffect(() => {
console.log("I run when 'counter' changes.");
}, [counter]);
// keyword 또는 counter가 변할때 다시 렌더링
useEffect(() => {
console.log('I run when keyword & counter change.');
}, [keyword, counter]);
return (
<div>
<input
value={keyword}
onChange={onChange}
type="text"
placeholder="Search here...."
/>
<h1>{counter}</h1>
<button onClick={onClick}>Click me</button>
</div>
);
}
export default App;
cleanup function import { useState, useEffect } from 'react';
function Hello() {
useEffect(() => {
console.log('created :)');
//cleanup function(컴포넌트가 destroy될때 사용)
//ex.컴포넌트가 없어질때 어떤 분석 결과를 보내고 싶을때,
//또는 eventlistener를 지우고 싶을때
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;
react-router-dom import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Detail from './routes/Detail';
import Home from './routes/Home';
function App() {
//switch는 route를 찾아서 컴포넌트를 렌더링 .
//한번에 하나의 route만 렌더링 하기 위해서 switch 씀.
return (
<Router>
<Switch>
<Route path="/movie/:id">
<Detail />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
export default App;
import PropTypes from 'prop-types';
//Link는 브라우저 새로고침 없이도 유저를 다른 페이지로 이동 시켜주는 컴포넌트.
import { Link } from 'react-router-dom';
import styles from './Movie.module.css';
function Movie({ id, coverImg, title, year, summary, genres }) {
return (
<div className={styles.movie}>
<img className={styles.movie__img} src={coverImg} alt={title} />
<div>
<h2 className={styles.movie__title}>
<Link to={`/movie/${id}`}>{title}</Link>
</h2>
<h3 className={styles.movie__year}>{year}</h3>
<p>{summary.length > 235 ? `${summary.slice(0, 235)}...` : summary}</p>
<ul className={styles.movie__genres}>
{genres.map((g, index) => (
<li key={index}>{g}</li>
))}
</ul>
</div>
</div>
);
}
Movie.propTypes = {
id: PropTypes.number.isRequired,
coverImg: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
summary: PropTypes.string.isRequired,
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
};
export default Movie;
parameter //useparams는 react router의 변수 값을 넘겨줌.
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import styles from './Detail.module.css';
function Detail() {
const [loading, setLoading] = useState(true);
const [movie, setMovie] = useState([]);
const { id } = useParams();
const getMovie = useCallback(async () => {
const json = await (
await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
).json();
setMovie(json.data.movie);
setLoading(false);
}, [id]);
useEffect(() => {
getMovie();
}, [getMovie]);
return (
<div className={styles.loader}>
{loading ? (
<h1>Loading...</h1>
) : (
<div className={styles.movie}>
<img
className={styles.img}
src={movie.medium_cover_image}
alt={movie.title}
/>
<div>
<h1>{movie.title}</h1>
<p>{movie.description_intro}</p>
<p>language: {movie.language}</p>
<p>Rating: {movie.rating}</p>
<p>Year: {movie.year}</p>
</div>
</div>
)}
</div>
);
}
export default Detail;
ダウンジャケットページ配布
npm i gh-pages
1.npm run buildを実行すると、Webサイトの本番準備コードが生成されます.
production readyとは,コードが圧縮され,すべてが最適化されることである.
実行するとbuildというフォルダが作成されます
コードを最初のプレゼンテーションでのみ実行し、他のステータスが変化したときに実行しないようにします.
例)APIを使用してデータを入力すると、構成部品レンダリングによってAPIが呼び出されます.
以降状態が変化した場合には、APIからのデータの再取得を避けることができる
useEffect(callback, [])
:一般的な使用法=>APIは1回のみ呼び出され、これ以上呼び出されたくない
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);
};
// 한번만 렌더링 되고 실행안됨.
// 아무것도 보고 있지 않기 때문에.
useEffect(() => {
console.log('i run only once.');
}, []);
// keyword가 변할때만 다시 렌더링
useEffect(() => {
console.log("I run when 'keyword' changes.");
}, [keyword]);
// counter가 변할때만 다시 렌더링
useEffect(() => {
console.log("I run when 'counter' changes.");
}, [counter]);
// keyword 또는 counter가 변할때 다시 렌더링
useEffect(() => {
console.log('I run when keyword & counter change.');
}, [keyword, counter]);
return (
<div>
<input
value={keyword}
onChange={onChange}
type="text"
placeholder="Search here...."
/>
<h1>{counter}</h1>
<button onClick={onClick}>Click me</button>
</div>
);
}
export default App;
cleanup function import { useState, useEffect } from 'react';
function Hello() {
useEffect(() => {
console.log('created :)');
//cleanup function(컴포넌트가 destroy될때 사용)
//ex.컴포넌트가 없어질때 어떤 분석 결과를 보내고 싶을때,
//또는 eventlistener를 지우고 싶을때
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;
react-router-dom import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Detail from './routes/Detail';
import Home from './routes/Home';
function App() {
//switch는 route를 찾아서 컴포넌트를 렌더링 .
//한번에 하나의 route만 렌더링 하기 위해서 switch 씀.
return (
<Router>
<Switch>
<Route path="/movie/:id">
<Detail />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
export default App;
import PropTypes from 'prop-types';
//Link는 브라우저 새로고침 없이도 유저를 다른 페이지로 이동 시켜주는 컴포넌트.
import { Link } from 'react-router-dom';
import styles from './Movie.module.css';
function Movie({ id, coverImg, title, year, summary, genres }) {
return (
<div className={styles.movie}>
<img className={styles.movie__img} src={coverImg} alt={title} />
<div>
<h2 className={styles.movie__title}>
<Link to={`/movie/${id}`}>{title}</Link>
</h2>
<h3 className={styles.movie__year}>{year}</h3>
<p>{summary.length > 235 ? `${summary.slice(0, 235)}...` : summary}</p>
<ul className={styles.movie__genres}>
{genres.map((g, index) => (
<li key={index}>{g}</li>
))}
</ul>
</div>
</div>
);
}
Movie.propTypes = {
id: PropTypes.number.isRequired,
coverImg: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
summary: PropTypes.string.isRequired,
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
};
export default Movie;
parameter //useparams는 react router의 변수 값을 넘겨줌.
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import styles from './Detail.module.css';
function Detail() {
const [loading, setLoading] = useState(true);
const [movie, setMovie] = useState([]);
const { id } = useParams();
const getMovie = useCallback(async () => {
const json = await (
await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
).json();
setMovie(json.data.movie);
setLoading(false);
}, [id]);
useEffect(() => {
getMovie();
}, [getMovie]);
return (
<div className={styles.loader}>
{loading ? (
<h1>Loading...</h1>
) : (
<div className={styles.movie}>
<img
className={styles.img}
src={movie.medium_cover_image}
alt={movie.title}
/>
<div>
<h1>{movie.title}</h1>
<p>{movie.description_intro}</p>
<p>language: {movie.language}</p>
<p>Rating: {movie.rating}</p>
<p>Year: {movie.year}</p>
</div>
</div>
)}
</div>
);
}
export default Detail;
ダウンジャケットページ配布
npm i gh-pages
1.npm run buildを実行すると、Webサイトの本番準備コードが生成されます.
production readyとは,コードが圧縮され,すべてが最適化されることである.
実行するとbuildというフォルダが作成されます
import { useState, useEffect } from 'react';
function Hello() {
useEffect(() => {
console.log('created :)');
//cleanup function(컴포넌트가 destroy될때 사용)
//ex.컴포넌트가 없어질때 어떤 분석 결과를 보내고 싶을때,
//또는 eventlistener를 지우고 싶을때
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 { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Detail from './routes/Detail';
import Home from './routes/Home';
function App() {
//switch는 route를 찾아서 컴포넌트를 렌더링 .
//한번에 하나의 route만 렌더링 하기 위해서 switch 씀.
return (
<Router>
<Switch>
<Route path="/movie/:id">
<Detail />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
);
}
export default App;
import PropTypes from 'prop-types';
//Link는 브라우저 새로고침 없이도 유저를 다른 페이지로 이동 시켜주는 컴포넌트.
import { Link } from 'react-router-dom';
import styles from './Movie.module.css';
function Movie({ id, coverImg, title, year, summary, genres }) {
return (
<div className={styles.movie}>
<img className={styles.movie__img} src={coverImg} alt={title} />
<div>
<h2 className={styles.movie__title}>
<Link to={`/movie/${id}`}>{title}</Link>
</h2>
<h3 className={styles.movie__year}>{year}</h3>
<p>{summary.length > 235 ? `${summary.slice(0, 235)}...` : summary}</p>
<ul className={styles.movie__genres}>
{genres.map((g, index) => (
<li key={index}>{g}</li>
))}
</ul>
</div>
</div>
);
}
Movie.propTypes = {
id: PropTypes.number.isRequired,
coverImg: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
summary: PropTypes.string.isRequired,
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
};
export default Movie;
parameter //useparams는 react router의 변수 값을 넘겨줌.
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import styles from './Detail.module.css';
function Detail() {
const [loading, setLoading] = useState(true);
const [movie, setMovie] = useState([]);
const { id } = useParams();
const getMovie = useCallback(async () => {
const json = await (
await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
).json();
setMovie(json.data.movie);
setLoading(false);
}, [id]);
useEffect(() => {
getMovie();
}, [getMovie]);
return (
<div className={styles.loader}>
{loading ? (
<h1>Loading...</h1>
) : (
<div className={styles.movie}>
<img
className={styles.img}
src={movie.medium_cover_image}
alt={movie.title}
/>
<div>
<h1>{movie.title}</h1>
<p>{movie.description_intro}</p>
<p>language: {movie.language}</p>
<p>Rating: {movie.rating}</p>
<p>Year: {movie.year}</p>
</div>
</div>
)}
</div>
);
}
export default Detail;
ダウンジャケットページ配布
npm i gh-pages
1.npm run buildを実行すると、Webサイトの本番準備コードが生成されます.
production readyとは,コードが圧縮され,すべてが最適化されることである.
実行するとbuildというフォルダが作成されます
//useparams는 react router의 변수 값을 넘겨줌.
import { useCallback, useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import styles from './Detail.module.css';
function Detail() {
const [loading, setLoading] = useState(true);
const [movie, setMovie] = useState([]);
const { id } = useParams();
const getMovie = useCallback(async () => {
const json = await (
await fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
).json();
setMovie(json.data.movie);
setLoading(false);
}, [id]);
useEffect(() => {
getMovie();
}, [getMovie]);
return (
<div className={styles.loader}>
{loading ? (
<h1>Loading...</h1>
) : (
<div className={styles.movie}>
<img
className={styles.img}
src={movie.medium_cover_image}
alt={movie.title}
/>
<div>
<h1>{movie.title}</h1>
<p>{movie.description_intro}</p>
<p>language: {movie.language}</p>
<p>Rating: {movie.rating}</p>
<p>Year: {movie.year}</p>
</div>
</div>
)}
</div>
);
}
export default Detail;
npm i gh-pages
1.npm run buildを実行すると、Webサイトの本番準備コードが生成されます.
production readyとは,コードが圧縮され,すべてが最適化されることである.
実行するとbuildというフォルダが作成されます
"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"
},
"homepage": "https://github계정이름.github.io/레포지토리이름"
gh-pagesでは-dはディレクトリです.predeployを作成する理由は、構築と導入が必要であることを知りたくないからです.
したがって、deploy、nodeを実行すると.jsはまずpredeployを実行する
その後、導入を開始します.
breaking changes
reactは、ツールの更新後に修復が必要な破壊的な変更は発生しません.
react query
便利な方法でデータを取得します.
実行中の論理を減らします.import { QueryClient, QueryClientProvider } from 'react-query';
const queryClient = new QueryClient();
ReactDOM.render(
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</QueryClientProvider>
document.getElementById('root')
);
fetcher関数を作成します.export function fetchCoins() {
return fetch('https://api.coinpaprika.com/v1/coins').then((response) =>
response.json()
);
}
// useQuery hook은 fetcher함수 fetchCoins를 부르고
//fetcher함수가 loading 중이라면 react query는 isLoading에 알려줌.
//fetcher함수가 끝난 값을 data에 넣어줄거임.
//react query는 데이터를 캐시에 저장.
const { isLoading, data } = useQuery<ICoin[]>('allCoins', fetchCoins);
recoil
国家図書館
react-hook-form
フォーム管理を容易にするパッケージ.
Reference
この問題について(react.js), 我々は、より多くの情報をここで見つけました
https://velog.io/@hrj0903/react.js
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
便利な方法でデータを取得します.
実行中の論理を減らします.
import { QueryClient, QueryClientProvider } from 'react-query';
const queryClient = new QueryClient();
ReactDOM.render(
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</QueryClientProvider>
document.getElementById('root')
);
fetcher関数を作成します.export function fetchCoins() {
return fetch('https://api.coinpaprika.com/v1/coins').then((response) =>
response.json()
);
}
// useQuery hook은 fetcher함수 fetchCoins를 부르고
//fetcher함수가 loading 중이라면 react query는 isLoading에 알려줌.
//fetcher함수가 끝난 값을 data에 넣어줄거임.
//react query는 데이터를 캐시에 저장.
const { isLoading, data } = useQuery<ICoin[]>('allCoins', fetchCoins);
recoil
国家図書館
react-hook-form
フォーム管理を容易にするパッケージ.
Reference
この問題について(react.js), 我々は、より多くの情報をここで見つけました
https://velog.io/@hrj0903/react.js
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
フォーム管理を容易にするパッケージ.
Reference
この問題について(react.js), 我々は、より多くの情報をここで見つけました https://velog.io/@hrj0903/react.jsテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol