2020 년에 React를 마스터하는 데 필요한 모든 개념과 기술에 대한 전체 시각적 치트 시트를 작성했습니다.
그러나 '치트 시트'라는 레이블이 당신을 속이게 하지 마십시오. 이것은 React의 기능을 요약 한 것 이상입니다.
여기서의 목표는 React와 전문 개발자로서의 작업을 통해 얻은 지식과 패턴을 명확하고 간결하게 제시하는 것이었습니다.
각 부분은 의미 있는 설명과 함께 실제적이고 실제적인 예를 보여줌으로써 많은 도움이 되도록 설계되었습니다.
자신의 사본을 원하십니까? ?
PDF 치트 시트를 여기에서 가져 오십시오 (5 초 소요).
다음은 다운로드 가능한 버전을 가져 오면 얻을 수 있는 빠른 결과입니다.
✓ 언제 어디서나 검토 할 수 있는 빠른 참조 안내서
✓ 쉽게 재사용 할 수 있는 수많은 복사 가능한 코드 스니펫
✓ 당신에게 가장 적합한 곳이라면 이 방대한 안내서를 읽으십시오. 기차, 책상, 줄 서서 ... 어디에서나
참고 :이 치트 시트에는 클래스 구성 요소의 범위가 제한되어 있습니다.
클래스 컴포넌트는 여전히 기존 React 프로젝트에서 알아야 할 가치가 있지만 2018 년에 Hooks가 출시 된 이후로 함수 컴포넌트만으로 앱을 만들 수 있습니다.
초보자와 숙련 된 개발자 모두에게 React의 후크 우선 접근 방식을 제공하고 싶었습니다.
다룰 훌륭한 것들이 많이 있으므로 시작합시다.
목차
핵심 개념
React Hooks
Advanced Hooks
핵심 개념
Elements and JSX
다음은 React 요소의 기본 구문입니다.
// In a nutshell, JSX allows us to write HTML in our JS
// JSX can use any valid html tags (i.e. div/span, h1-h6, form/input, etc)
<div>Hello React</div>
JSX 요소는 표현식입니다.
// as an expression, JSX can be assigned to variables...
const greeting = <div>Hello React</div>;
const isNewToReact = true;
// ... or can be displayed conditionally
function sayGreeting() {
if (isNewToReact) {
// ... or returned from functions, etc.
return greeting; // displays: Hello React
} else {
return <div>Hi again, React</div>;
}
}
JSX를 사용하면 표현식을 중첩 할 수 있습니다.
const year = 2020;
// we can insert primitive JS values in curly braces: {}
const greeting = <div>Hello React in {year}</div>;
// trying to insert objects will result in an error
JSX를 사용하면 요소를 중첩 할 수 있습니다.
// to write JSX on multiple lines, wrap in parentheses: ()
const greeting = (
// div is the parent element
<div>
{/* h1 and p are child elements */}
<h1>Hello!</h1>
<p>Welcome to React</p>
</div>
);
// 'parents' and 'children' are how we describe JSX elements in relation
// to one another, like we would talk about HTML elements
HTML과 JSX의 구문은 약간 다릅니다.
// Empty div is not <div></div> (HTML), but <div/> (JSX)
<div/>
// A single tag element like input is not <input> (HTML), but <input/> (JSX)
<input name="email" />
// Attributes are written in camelcase for JSX (like JS variables
<button className="submit-button">Submit</button> // not 'class' (HTML)
가장 기본적인 React 앱에는 세 가지가 필요합니다.
// imports needed if using NPM package; not if from CDN links
import React from "react";
import ReactDOM from "react-dom";
const greeting = <h1>Hello React</h1>;
// ReactDOM.render(root node, mounting point)
ReactDOM.render(greeting, document.getElementById("root"));
Components and Props
다음은 기본 React 컴포넌트의 구문입니다.
import React from "react";
// 1st component type: function component
function Header() {
// function components must be capitalized unlike normal JS functions
// note the capitalized name here: 'Header'
return <h1>Hello React</h1>;
}
// function components with arrow functions are also valid
const Header = () => <h1>Hello React</h1>;
// 2nd component type: class component
// (classes are another type of function)
class Header extends React.Component {
// class components have more boilerplate (with extends and render method)
render() {
return <h1>Hello React</h1>;
}
}
컴포넌트가 사용되는 방식입니다.
// do we call these function components like normal functions?
// No, to execute them and display the JSX they return...
const Header = () => <h1>Hello React</h1>;
// ...we use them as 'custom' JSX elements
ReactDOM.render(<Header />, document.getElementById("root"));
// renders: <h1>Hello React</h1>
앱에서 컴포넌트를 재사용 할 수 있습니다.
// for example, this Header component can be reused in any app page
// this component shown for the '/' route
function IndexPage() {
return (
<div>
<Header />
<Hero />
<Footer />
</div>
);
}
// shown for the '/about' route
function AboutPage() {
return (
<div>
<Header />
<About />
<Testimonials />
<Footer />
</div>
);
}
props을 사용하여 데이터를 구성 요소에 동적으로 전달할 수 있습니다.
// What if we want to pass data to our component from a parent?
// I.e. to pass a user's name to display in our Header?
const username = "John";
// we add custom 'attributes' called props
ReactDOM.render(
<Header username={username} />,
document.getElementById("root")
);
// we called this prop 'username', but can use any valid JS identifier
// props is the object that every component receives as an argument
function Header(props) {
// the props we make on the component (i.e. username)
// become properties on the props object
return <h1>Hello {props.username}</h1>;
}
Props은 절대 직접 변경 (변이)해서는 안됩니다.
// Components must ideally be 'pure' functions.
// That is, for every input, we be able to expect the same output
// we cannot do the following with props:
function Header(props) {
// we cannot mutate the props object, we can only read from it
props.username = "Doug";
return <h1>Hello {props.username}</h1>;
}
// But what if we want to modify a prop value that comes in?
// That's where we would use state (see the useState section)
하위 props은 요소 / 구성 요소를 다른 구성 요소에 props으로 전달하려는 경우 유용합니다.
// Can we accept React elements (or components) as props?
// Yes, through a special property on the props object called 'children'
function Layout(props) {
return <div className="container">{props.children}</div>;
}
// The children prop is very useful for when you want the same
// component (such as a Layout component) to wrap all other components:
function IndexPage() {
return (
<Layout>
<Header />
<Hero />
<Footer />
</Layout>
);
}
// different page, but uses same Layout component (thanks to children prop)
function AboutPage() {
return (
<Layout>
<About />
<Footer />
</Layout>
);
}
삼항 및 단락이 있는 구성 요소를 조건부로 표시 :
// if-statements are fine to conditionally show , however...
// ...only ternaries (seen below) allow us to insert these conditionals
// in JSX, however
function Header() {
const isAuthenticated = checkAuth();
return (
<nav>
<Logo />
{/* if isAuth is true, show AuthLinks. If false, Login */}
{isAuthenticated ? <AuthLinks /> : <Login />}
{/* if isAuth is true, show Greeting. If false, nothing. */}
{isAuthenticated && <Greeting />}
</nav>
);
}
단편은 DOM에 추가 요소를 추가하지 않고 여러 구성 요소를 표시하기 위한 특수 구성 요소입니다.
조각은 조건부 논리에 이상적입니다.
// we can improve the logic in the previous example
// if isAuthenticated is true, how do we display both AuthLinks and Greeting?
function Header() {
const isAuthenticated = checkAuth();
return (
<nav>
<Logo />
{/* we can render both components with a fragment */}
{/* fragments are very concise: <> </> */}
{isAuthenticated ? (
<>
<AuthLinks />
<Greeting />
</>
) : (
<Login />
)}
</nav>
);
}
리스트와 키
.map()을 사용하여 데이터 목록 (배열)을 요소 목록으로 변환하십시오.
const people = ["John", "Bob", "Fred"];
const peopleList = people.map(person => <p>{person}</p>);
.map()은 구성 요소 및 요소에도 사용됩니다.
function App() {
const people = ['John', 'Bob', 'Fred'];
// can interpolate returned list of elements in {}
return (
<ul>
{/* we're passing each array element as props */}
{people.map(person => <Person name={person} />}
</ul>
);
}
function Person({ name }) {
// gets 'name' prop using object destructuring
return <p>this person's name is: {name}</p>;
}
반복 된 각 React 요소에는 특별한 '키'소품이 필요합니다. React가 맵으로 반복되는 각 요소를 추적하려면 키가 필수적입니다.
키가 없으면 데이터가 변경 될 때 요소를 업데이트하는 방법을 파악하기가 더 어렵습니다.
키는 이러한 요소가 서로 분리되어 있다는 사실을 나타내기 위해 고유 한 값이어야 합니다.
function App() {
const people = ['John', 'Bob', 'Fred'];
return (
<ul>
{/* keys need to be primitive values, ideally a generated id */}
{people.map(person => <Person key={person} name={person} />)}
</ul>
);
}
// If you don't have ids with your set of data or unique primitive values,
// you can use the second parameter of .map() to get each elements index
function App() {
const people = ['John', 'Bob', 'Fred'];
return (
<ul>
{/* use array element index for key */}
{people.map((person, i) => <Person key={i} name={person} />)}
</ul>
);
}
이벤트 및 이벤트 처리기
React와 HTML의 이벤트는 약간 다릅니다.
// Note: most event handler functions start with 'handle'
function handleToggleTheme() {
// code to toggle app theme
}
// in html, onclick is all lowercase
<button onclick="handleToggleTheme()">
Submit
</button>
// in JSX, onClick is camelcase, like attributes / props
// we also pass a reference to the function with curly braces
<button onClick={handleToggleTheme}>
Submit
</button>
알아야 할 가장 중요한 React 이벤트는 onClick 및 onChange입니다.
function App() {
function handleChange(event) {
// when passing the function to an event handler, like onChange
// we get access to data about the event (an object)
const inputText = event.target.value;
const inputName = event.target.name; // myInput
// we get the text typed in and other data from event.target
}
function handleSubmit() {
// on click doesn't usually need event data
}
return (
<div>
<input type="text" name="myInput" onChange={handleChange} />
<button onClick={handleSubmit}>Submit</button>
</div>
);
}
React Hooks
State and useState
useState는 함수 구성 요소에서 로컬 상태를 제공합니다.
import React from 'react';
// create state variable
// syntax: const [stateVariable] = React.useState(defaultValue);
function App() {
const [language] = React.useState('javascript');
// we use array destructuring to declare state variable
return <div>I am learning {language}</div>;
}
참고 :이 섹션의 후크는 React 패키지에서 가져 오며 개별적으로 가져올 수 있습니다.
import React, { useState } from "react";
function App() {
const [language] = useState("javascript");
return <div>I am learning {language}</div>;
}
useState는 또한 생성 상태를 업데이트하는 'setter'함수를 제공합니다.
function App() {
// the setter function is always the second destructured value
const [language, setLanguage] = React.useState("python");
// the convention for the setter name is 'setStateVariable'
return (
<div>
{/* why use an arrow function here instead onClick={setterFn()} ? */}
<button onClick={() => setLanguage("javascript")}>
Change language to JS
</button>
{/* if not, setLanguage would be called immediately and not on click */}
<p>I am now learning {language}</p>
</div>
);
}
// note that whenever the setter function is called, the state updates,
// and the App component re-renders to display the new state
useState는 단일 구성 요소 내에서 한 번 또는 여러 번 사용할 수 있습니다.
function App() {
const [language, setLanguage] = React.useState("python");
const [yearsExperience, setYearsExperience] = React.useState(0);
return (
<div>
<button onClick={() => setLanguage("javascript")}>
Change language to JS
</button>
<input
type="number"
value={yearsExperience}
onChange={event => setYearsExperience(event.target.value)}
/>
<p>I am now learning {language}</p>
<p>I have {yearsExperience} years of experience</p>
</div>
);
}
useState는 프리미티브 또는 객체 값을 수락하여 상태를 관리 할 수 있습니다.
// we have the option to organize state using whatever is the
// most appropriate data type, according to the data we're tracking
function App() {
const [developer, setDeveloper] = React.useState({
language: "",
yearsExperience: 0
});
function handleChangeYearsExperience(event) {
const years = event.target.value;
// we must pass in the previous state object we had with the spread operator
setDeveloper({ ...developer, yearsExperience: years });
}
return (
<div>
{/* no need to get prev state here; we are replacing the entire object */}
<button
onClick={() =>
setDeveloper({
language: "javascript",
yearsExperience: 0
})
}
>
Change language to JS
</button>
{/* we can also pass a reference to the function */}
<input
type="number"
value={developer.yearsExperience}
onChange={handleChangeYearsExperience}
/>
<p>I am now learning {developer.language}</p>
<p>I have {developer.yearsExperience} years of experience</p>
</div>
);
}
새 상태가 이전 상태에 의존하는 경우 업데이트가 안정적으로 수행되도록 setter 함수 내에서 올바른 이전 상태를 제공하는 함수를 사용할 수 있습니다.
function App() {
const [developer, setDeveloper] = React.useState({
language: "",
yearsExperience: 0,
isEmployed: false
});
function handleToggleEmployment(event) {
// we get the previous state variable's value in the parameters
// we can name 'prevState' however we like
setDeveloper(prevState => {
return { ...prevState, isEmployed: !prevState.isEmployed };
// it is essential to return the new state from this function
});
}
return (
<button onClick={handleToggleEmployment}>Toggle Employment Status</button>
);
}
Side effects and useEffect
useEffect를 사용하면 함수 구성 요소에서 부작용을 수행 할 수 있습니다. 그렇다면 부작용은 무엇입니까?
useEffect는 다시 렌더링 할 때마다 기본적으로 실행되는 콜백 함수 ( '효과'함수)를 허용합니다. 컴포넌트가 마운트 되면 실행되는데, 이는 컴포넌트 라이프 사이클에서 부작용을 수행하기에 적절한 시기입니다.
// what does our code do? Picks a color from the colors array
// and makes it the background color
function App() {
const [colorIndex, setColorIndex] = React.useState(0);
const colors = ["blue", "green", "red", "orange"];
// we are performing a 'side effect' since we are working with an API
// we are working with the DOM, a browser API outside of React
useEffect(() => {
document.body.style.backgroundColor = colors[colorIndex];
});
// whenever state is updated, App re-renders and useEffect runs
function handleChangeIndex() {
const next = colorIndex + 1 === colors.length ? 0 : colorIndex + 1;
setColorIndex(next);
}
return <button onClick={handleChangeIndex}>Change background color</button>;
}
각 렌더링 후 효과 콜백을 실행하지 않으려면 빈 배열 인 두 번째 인수를 제공합니다.
function App() {
...
// now our button doesn't work no matter how many times we click it...
useEffect(() => {
document.body.style.backgroundColor = colors[colorIndex];
}, []);
// the background color is only set once, upon mount
// how do we not have the effect function run for every state update...
// but still have it work whenever the button is clicked?
return (
<button onClick={handleChangeIndex}>
Change background color
</button>
);
}
useEffect를 사용하면 종속성 배열로 조건부 효과를 수행 할 수 있습니다.
종속성 배열은 두 번째 인수이며 배열의 값 중 하나가 변경되면 효과 함수가 다시 실행됩니다.
function App() {
const [colorIndex, setColorIndex] = React.useState(0);
const colors = ["blue", "green", "red", "orange"];
// we add colorIndex to our dependencies array
// when colorIndex changes, useEffect will execute the effect fn again
useEffect(() => {
document.body.style.backgroundColor = colors[colorIndex];
// when we use useEffect, we must think about what state values
// we want our side effect to sync with
}, [colorIndex]);
function handleChangeIndex() {
const next = colorIndex + 1 === colors.length ? 0 : colorIndex + 1;
setColorIndex(next);
}
return <button onClick={handleChangeIndex}>Change background color</button>;
}
useEffect를 사용하면 마지막에 함수를 반환하여 특정 효과를 구독 취소 할 수 있습니다.
function MouseTracker() {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
React.useEffect(() => {
// .addEventListener() sets up an active listener...
window.addEventListener("mousemove", event => {
const { pageX, pageY } = event;
setMousePosition({ x: pageX, y: pageY });
});
// ...so when we navigate away from this page, it needs to be
// removed to stop listening. Otherwise, it will try to set
// state in a component that doesn't exist (causing an error)
// We unsubscribe any subscriptions / listeners w/ this 'cleanup function'
return () => {
window.removeEventListener("mousemove", event => {
const { pageX, pageY } = event;
setMousePosition({ x: pageX, y: pageY });
});
};
}, []);
return (
<div>
<h1>The current mouse position is:</h1>
<p>
X: {mousePosition.x}, Y: {mousePosition.y}
</p>
</div>
);
}
// Note: we could extract the reused logic in the callbacks to
// their own function, but I believe this is more readable
보다 간결한 async / await 구문으로 약속을 처리하려면 별도의 함수를 만들어야 합니다. (왜? 효과 콜백 함수는 비 동기화 할 수 없습니다.)
const endpoint = "https://api.github.com/users/codeartistryio";
// with promises:
function App() {
const [user, setUser] = React.useState(null);
React.useEffect(() => {
// promises work in callback
fetch(endpoint)
.then(response => response.json())
.then(data => setUser(data));
}, []);
}
// with async / await syntax for promise:
function App() {
const [user, setUser] = React.useState(null);
// cannot make useEffect callback function async
React.useEffect(() => {
getUser();
}, []);
// instead, use async / await in separate function, then call
// function back in useEffect
async function getUser() {
const response = await fetch("https://api.github.com/codeartistryio");
const data = await response.json();
setUser(data);
}
}
Performance and useCallback
useCallback은 컴포넌트의 성능을 향상 시키는 데 사용되는 후크입니다.
자주 다시 렌더링 하는 구성 요소가 있는 경우 useCallback은 구성 요소를 다시 렌더링 할 때마다 구성 요소 내의 콜백 함수가 다시 생성되지 않도록 합니다 (즉, 기능 구성 요소가 다시 실행 됨).
useCallback은 종속성 중 하나가 변경 될 때만 다시 실행됩니다.
// in Timer, we are calculating the date and putting it in state a lot
// this results in a re-render for every state update
// we had a function handleIncrementCount to increment the state 'count'...
function Timer() {
const [time, setTime] = React.useState();
const [count, setCount] = React.useState(0);
// ... but unless we wrap it in useCallback, the function is
// recreated for every single re-render (bad performance hit)
// useCallback hook returns a callback that isn't recreated every time
const inc = React.useCallback(
function handleIncrementCount() {
setCount(prevCount => prevCount + 1);
},
// useCallback accepts a second arg of a dependencies array like useEffect
// useCallback will only run if any dependency changes (here it's 'setCount')
[setCount]
);
React.useEffect(() => {
const timeout = setTimeout(() => {
const currentTime = JSON.stringify(new Date(Date.now()));
setTime(currentTime);
}, 300);
return () => {
clearTimeout(timeout);
};
}, [time]);
return (
<div>
<p>The current time is: {time}</p>
<p>Count: {count}</p>
<button onClick={inc}>+</button>
</div>
);
}
Memoization and useMemo
useMemo는 useCallback과 매우 유사하며 성능 향상을 위한 것입니다. 그러나 콜백 대신 값 비싼 계산 결과를 저장하기 위한 것입니다.
useMemo를 사용하면 특정 입력에 대해 이미 작성된 값 비싼 계산의 결과를 '기억'하거나 기억할 수 있습니다 (이러한 값에 대해 이미 한 번 수행 했으므로 다시 수행하는 것은 새로운 일이 아닙니다).
useMemo는 콜백 함수가 아니라 계산에서 값을 반환합니다 (그러나 함수일 수 있음).
// useMemo is useful when we need a lot of computing resources
// to perform an operation, but don't want to repeat it on each re-render
function App() {
// state to select a word in 'words' array below
const [wordIndex, setWordIndex] = useState(0);
// state for counter
const [count, setCount] = useState(0);
// words we'll use to calculate letter count
const words = ["i", "am", "learning", "react"];
const word = words[wordIndex];
function getLetterCount(word) {
// we mimic expensive calculation with a very long (unnecessary) loop
let i = 0;
while (i < 1000000) i++;
return word.length;
}
// Memoize expensive function to return previous value if input was the same
// only perform calculation if new word without a cached value
const letterCount = React.useMemo(() => getLetterCount(word), [word]);
// if calculation was done without useMemo, like so:
// const letterCount = getLetterCount(word);
// there would be a delay in updating the counter
// we would have to wait for the expensive function to finish
function handleChangeIndex() {
// flip from one word in the array to the next
const next = wordIndex + 1 === words.length ? 0 : wordIndex + 1;
setWordIndex(next);
}
return (
<div>
<p>
{word} has {letterCount} letters
</p>
<button onClick={handleChangeIndex}>Next word</button>
<p>Counter: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
Refs and useRef
참조는 모든 React 구성 요소에서 사용할 수 있는 특수 속성입니다. 그것들은 컴포넌트가 마운트 될 때 주어진 요소 / 컴포넌트에 대한 참조를 만들 수 있습니다
useRef를 사용하면 React 참조를 쉽게 사용할 수 있습니다. 컴포넌트의 최상위에 있는 useRef를 호출하고 반환 된 값을 요소의 ref 속성에 첨부하여 참조합니다.
참조를 만든 후에는 현재 속성을 사용하여 요소의 속성을 수정 (돌연변이)합니다. 또는 해당 요소에서 사용 가능한 메소드 (예 : 입력을 집중 시키기 위해 .focus ())를 호출 할 수 있습니다.
function App() {
const [query, setQuery] = React.useState("react hooks");
// we can pass useRef a default value
// we don't need it here, so we pass in null to ref an empty object
const searchInput = useRef(null);
function handleClearSearch() {
// current references the text input once App mounts
searchInput.current.value = "";
// useRef can store basically any value in its .current property
searchInput.current.focus();
}
return (
<form>
<input
type="text"
onChange={event => setQuery(event.target.value)}
ref={searchInput}
/>
<button type="submit">Search</button>
<button type="button" onClick={handleClearSearch}>
Clear
</button>
</form>
);
}
Advanced Hooks
Context and useContext
React에서는 부모 구성 요소에서 두 개 이상의 수준으로 데이터를 전달하기 위해 여러 소품을 만드는 다음과 같은 문제를 피하고 싶습니다.
// Context helps us avoid creating multiple duplicate props
// This pattern is also called props drilling:
function App() {
// we want to pass user data down to Header
const [user] = React.useState({ name: "Fred" });
return (
{/* first 'user' prop */}
<Main user={user} />
);
}
const Main = ({ user }) => (
<>
{/* second 'user' prop */}
<Header user={user} />
<div>Main app content...</div>
</>
);
const Header = ({ user }) => <header>Welcome, {user.name}!</header>;
컨텍스트는 부모 컴포넌트에서 여러 레벨의 하위 컴포넌트로 소품을 전달하는 데 도움이 됩니다.
// Here is the previous example rewritten with Context
// First we create context, where we can pass in default values
const UserContext = React.createContext();
// we call this 'UserContext' because that's what data we're passing down
function App() {
// we want to pass user data down to Header
const [user] = React.useState({ name: "Fred" });
return (
{/* we wrap the parent component with the provider property */}
{/* we pass data down the computer tree w/ value prop */}
<UserContext.Provider value={user}>
<Main />
</UserContext.Provider>
);
}
const Main = () => (
<>
<Header />
<div>Main app content...</div>
</>
);
// we can remove the two 'user' props, we can just use consumer
// to consume the data where we need it
const Header = () => (
{/* we use this pattern called render props to get access to the data*/}
<UserContext.Consumer>
{user => <header>Welcome, {user.name}!</header>}
</UserContext.Consumer>
);
그러나 useContext 후크를 사용하면 이 비정상적으로 보이는 렌더 소품 패턴을 제거하여 원하는 함수 구성 요소에서 컨텍스트를 사용할 수 있습니다.
const Header = () => {
// we pass in the entire context object to consume it
const user = React.useContext(UserContext);
// and we can remove the Consumer tags
return <header>Welcome, {user.name}!</header>;
};
Reducers and useReducer
감속기는 이전 상태 개체와 동작 개체를 가져 와서 새로운 상태 개체를 반환하는 단순하고 예측 가능한 (순수한) 함수입니다. 예를 들면 다음과 같습니다.
// let's say this reducer manages user state in our app:
function reducer(state, action) {
// reducers often use a switch statement to update state
// in one way or another based on the action's type property
switch (action.type) {
// if action.type has the string 'LOGIN' on it
case "LOGIN":
// we get data from the payload object on action
return { username: action.payload.username, isAuth: true };
case "SIGNOUT":
return { username: "", isAuth: false };
default:
// if no case matches, return previous state
return state;
}
}
리듀서는 널리 사용되는 상태 관리 라이브러리 인 Redux (일반적으로 React와 함께 사용)에서 사용되는 상태 관리를 위한 강력한 패턴입니다.
리덕터는 useState (로컬 컴포넌트 상태에 해당)와 비교하여 앱 전체에서 상태를 관리하기 위해 useReducer 후크와 함께 React에서 사용될 수 있습니다.
따라서 useReducer + useContext는 앱의 전체 상태 관리 시스템이 될 수 있습니다.
const initialState = { username: "", isAuth: false };
function reducer(state, action) {
switch (action.type) {
case "LOGIN":
return { username: action.payload.username, isAuth: true };
case "SIGNOUT":
// could also spread in initialState here
return { username: "", isAuth: false };
default:
return state;
}
}
function App() {
// useReducer requires a reducer function to use and an initialState
const [state, dispatch] = useReducer(reducer, initialState);
// we get the current result of the reducer on 'state'
// we use dispatch to 'dispatch' actions, to run our reducer
// with the data it needs (the action object)
function handleLogin() {
dispatch({ type: "LOGIN", payload: { username: "Ted" } });
}
function handleSignout() {
dispatch({ type: "SIGNOUT" });
}
return (
<>
Current user: {state.username}, isAuthenticated: {state.isAuth}
<button onClick={handleLogin}>Login</button>
<button onClick={handleSignout}>Signout</button>
</>
);
}
사용자 정의 후크 작성
구성 요소 간의 동작을 쉽게 재사용 하기 위해 후크가 작성되었습니다.
그것들은 고차 컴포넌트 또는 렌더 소품과 같은 클래스 컴포넌트의 이전 패턴보다 이해하기 쉬운 패턴입니다.
가장 좋은 점은 React가 제공하는 것 외에도 우리 프로젝트의 필요에 따라 자체 후크를 만들 수 있다는 것입니다.
// here's a custom hook that is used to fetch data from an API
function useAPI(endpoint) {
const [value, setValue] = React.useState([]);
React.useEffect(() => {
getData();
}, []);
async function getData() {
const response = await fetch(endpoint);
const data = await response.json();
setValue(data);
};
return value;
};
// this is a working example! try it yourself (i.e. in codesandbox.io)
function App() {
const todos = useAPI("https://todos-dsequjaojf.now.sh/todos");
return (
<ul>
{todos.map(todo => <li key={todo.id}>{todo.text}</li>}
</ul>
);
}
Rules of hooks
올바르게 작동하기 위해 위반할 수 없는 React 후크를 사용하는 두 가지 핵심 규칙이 있습니다.
function checkAuth() {
// Rule 2 Violated! Hooks cannot be used in normal functions, only components
React.useEffect(() => {
getUser();
}, []);
}
function App() {
// this is the only validly executed hook in this component
const [user, setUser] = React.useState(null);
// Rule 1 violated! Hooks cannot be used within conditionals (or loops)
if (!user) {
React.useEffect(() => {
setUser({ isAuth: false });
// if you want to conditionally execute an effect, use the
// dependencies array for useEffect
}, []);
}
checkAuth();
// Rule 1 violated! Hooks cannot be used in nested functions
return <div onClick={() => React.useMemo(() => doStuff(), [])}>Our app</div>;
}
무엇 향후 계획
배울 수 있는 다른 많은 React 개념이 있지만, 이것들은 2020 년 React 숙달의 길을 안내하기 위해 다른 사람들보다 먼저 알아야 할 것들입니다.
이러한 모든 개념에 대한 빠른 참조를 원하십니까?
이 모든 정보를 담은 완전한 PDF 치트 시트를 여기에서 다운로드하십시오.
계속 코딩하면 다음 기사에서 알려 드리겠습니다.
등록된 댓글이 없습니다.