Автор оригинала: FreeCodeCamp Community Member.
Я собрал всеобъемлющую Visual Chechsheet, чтобы помочь вам освоить все основные концепции и особенности библиотеки RACT в 2021 году.
Я создал эту Chechsheet, чтобы помочь вам оптимизировать свое исследование реагирования в кратчайшие сроки.
Он включает в себя тонны практических примеров для иллюстрации каждой особенности библиотеки и как она работает с использованием шаблонов, которые вы можете подать заявку в свои собственные проекты.
Наряду с каждым фрагментом кода я добавил много полезных комментариев. Если вы прочитаете эти комментарии, вы увидите, что делает каждую строку кода, как разные понятия относятся друг к другу и получают более полное понимание того, как реагировать.
Обратите внимание, что ключевые слова, которые особенно полезны для вас, чтобы узнать в качестве разработчика реагирования, выделены жирным шрифтом, поэтому смотрите на них.
Хотите вашу собственную копию чтевой таблицы?
Загрузите Chechseet в формате PDF здесь (Это занимает 5 секунд).
Вот несколько быстрых выигрышей от захвата загружаемой версии:
- ✓ Краткое справочное руководство по проверке, однако, и всякий раз, когда
- ✓ Тонны копироваемых фрагментов кода для простого повторного использования
- ✓ Прочитайте это массивное руководство везде, куда лучше вас подходит. На поезде, на вашем столе, стоя в очереди … где угодно.
Есть тонна отличных вещей, чтобы начать.
Оглавление
Реагистрационные основы
- Jsx элементы
- Компоненты и реквизиты
- Списки и ключи
- Слушатели событий и обработка событий
Основные реактивные крючки
- Государство и утилизация
- Побочные эффекты и использование
- Refs и Useref.
Крючки и производительность
- Предотвращение рендеров и реагирования. Мэмо
- Функции обратного вызова и USECallback
- Мемонизация и упреждающие
Усовершенствованные реактивный крючки
- Контекст и упреждающий текст
- Редукторы и упредверс
- Писать пользовательские крючки
- Правила крючков
Реагистрационные основы
Jsx элементы
Приложения React Structured с использованием синтаксиса под названием Jsx Отказ Это синтаксис базового Jsx элемент Отказ
/* JSX allows us to write in a syntax almost identical to plain HTML. As a result, JSX is a powerful tool to structure our applications. JSX uses all valid HTML tags (i.e. div/span, h1-h6, form/input, img, etc). */Hello React!/* Note: this JSX would not be visible because it needs to be rendered by our application using ReactDOM.render() */
JSX является наиболее распространенным способом структурирования приложений RACT, но оно не требуется для реагирования.
/* JSX is a simpler way to use the function React.createElement() In other words, the following two lines in React are the same: */Hello React!// JSX syntax React.createElement('div', null, 'Hello React!'); // createElement syntax
JSX не понимается браузером. Он должен быть скомпилирован на простое JavaScript, который может понять браузер.
Наиболее часто используемый компилятор для JSX называется Babel.
/* When our project is built to run in the browser, our JSX will be converted by Babel into simple React.createElement() function calls. From this... */ const greeting =Hello React!; /* ...into this: */ "use strict"; const greeting = /*#__PURE__*/React.createElement("div", null, "Hello React!");
JSX отличается от HTML несколько важных способов:
/* We can write JSX like plain HTML, but it's actually made using JavaScript functions. Because JSX is JavaScript, not HTML, there are some differences: 1) Some JSX attributes are named differently than HTML attributes. Why? Because some attribute words are reserved words in JavaScript, such as 'class'. Instead of class, JSX uses 'className'. Also, because JSX is JavaScript, attributes that consist of multiple words are written in camelcase: *//* 2) JSX elements that consist of only a single tag (i.e. input, img, br elements) must be closed with a trailing forward slash to be valid (/): */ // is a syntax error /* 3) JSX elements that consist of an opening and closing tag (i.e. div, span, button element), must have both or be closed with a trailing forward slash. Like 2), it is a syntax error to have an unterminated element. */ // is a syntax error // empty, but also validHello React!
Встроенные стили могут быть добавлены в элементы JSX, используя атрибут стиля. И стили обновляются в объекте, а не набор двойных кавычек, как с HTML.
Обратите внимание, что имена свойств стилей должны быть также написаны в камере.
/* Properties that accept pixel values (like width, height, padding, margin, etc), can use integers instead of strings. For example: fontSize: 22. Instead of: fontSize: "22px" */Hello React!
Элементы JSX являются выражениями JavaScript и могут использоваться как таковые. JSX дает нам полную мощность JavaScript прямо в нашем пользовательском интерфейсе.
/* JSX elements are expressions (resolve to a value) and therefore can be assigned to plain JavaScript variables... */ const greeting =Hello React!; const isNewToReact = true; // ... or can be displayed conditionally function sayGreeting() { if (isNewToReact) { // ... or returned from functions, etc. return greeting; // displays: Hello React! } else { returnHi again, React; } }
JSX позволяет нам вставлять (или встроить) простые выражения JavaScript с помощью синтаксиса финтии фигурных скобок:
const year = 2021; /* We can insert primitive JS values (i.e. strings, numbers, booleans) in curly braces: {} */ const greeting =Hello React in {year}; /* We can also insert expressions that resolve to a primitive value: */ const goodbye =Goodbye previous year: {year - 1}/* Expressions can also be used for element attributes */ const className = 'title'; const title =My title
/* Note: trying to insert object values (i.e. objects, arrays, maps) in curly braces will result in an error */
JSX позволяет нам гнездить элементами в другом, как и HTML.
/* To write JSX on multiple lines, wrap in parentheses: () JSX expressions that span multiple lines are called multiline expressions */ const greeting = ( // div is the parent element{/* h1 and p are child elements */}); /* 'parents' and 'children' are how we describe JSX elements in relation to one another, like we would talk about HTML elements */Hello!
Welcome to React
Комментарии в JSX записываются как Multiline JavaScript Comments, написанные между фигурными брекетами, как это:
const greeting = ({/* This is a single line comment */}Hello!
Welcome to React
{/* This is a multiline comment */}
Все приложения React требуют трех вещей:
Reactom.runder ()
: Используется для рендеринга (показать) наше приложение, установив его на HTML-элемент- Элемент JSX: называется «корневым узлом», потому что он является корнем нашего приложения. Значение, рендеринг он оказывает всех детей в нем
- Элемент HTML (DOM): где приложение вставляется на страницу HTML. Элемент обычно является div с идентификатором “root”, расположенный в файле index.html.
// Packages can be installed locally or brought in through a CDN link (added to head of HTML document) import React from "react"; import ReactDOM from "react-dom"; // root node (usually a component) is most often called "App" const App =Hello React!
; // ReactDOM.render(root node, HTML element) ReactDOM.render(App, document.getElementById("root"));
Компоненты и реквизиты
JSX может быть сгруппирован вместе в отдельных функциях под названием Компоненты Отказ
Существует два типа компонентов в реакции: Функциональные компоненты и Компоненты класса Отказ
Компонентные имена, для компонентов функции или классов, заглавны, чтобы отличить их от простых функций JavaScript, которые не возвращают JSX:
import React from "react"; /* Function component Note the capitalized function name: 'Header', not 'header' */ function Header() { returnHello React
; } // Function components which use an arrow function syntax are also valid const Header = () =>Hello React
; /* Class component Class components have more boilerplate (note the 'extends' keyword and 'render' method) */ class Header extends React.Component { render() { returnHello React
; } }
Компоненты, несмотря на функции, не называются как обычные функции JavaScript. Они выполняются путем рендеринга, как мы бы JSX в нашем приложении.
// Do we call this function component like a normal function? // No, to execute them and display the JSX they return... const Header = () =>Hello React
; // ...we use them as 'custom' JSX elements ReactDOM.render(, document.getElementById("root")); // renders: Hello React
Огромное преимущество компонентов – их способность использовать повторно использовать в наших приложениях, где бы нам ни понадобятся.
Поскольку компоненты используют мощность функций JavaScript, мы можем логически передавать данные для них, как мы, передаваем его один или несколько аргументов.
/* The Header and Footer components can be reused in any page in our app. Components remove the need to rewrite the same JSX multiple times. */ // IndexPage component, visible on '/' route of our app function IndexPage() { return (); } // AboutPage component, visible on the '/about' route function AboutPage() { return ( ); }
Данные, переданные на компоненты в JavaScript, называются реквизит Отказ Реквиты выглядят идентичны атрибуты на простых элементах JSX/HTML, но вы можете получить доступ к своим значениям в самой компонент.
Реквисы доступны по параметрам компонента, к которому они передаются. Реквисы всегда включены в качестве свойств объекта.
/* What if we want to pass custom data to our component from a parent component? For example, to display the user's name in our app header. */ const username = "John"; /* To do so, we add custom 'attributes' to our component called props. We can add many of them as we like and we give them names that suit the data we pass in. To pass the user's name to the header, we use a prop we appropriately called 'username' */ ReactDOM.render(, document.getElementById("root") ); // We called this prop 'username', but can use any valid identifier we would give, for example, a JavaScript variable // props is the object that every component receives as an argument function Header(props) { // the props we make on the component (username) // become properties on the props object return Hello {props.username}
; }
Реквисы никогда не должны быть напрямую изменены в пределах дочернего компонента.
Еще один способ сказать, что реквизиты никогда не должны быть Мутировал Поскольку реквизиты – это простой объект JavaScript.
/* Components should operate as 'pure' functions. That is, for every input, we should be able to expect the same output. This means we cannot mutate the props object, only read from it. */ // We cannot modify the props object : function Header(props) { props.username = "Doug"; returnHello {props.username}
; } /* But what if we want to modify a prop value that is passed to our component? That's where we would use state (see the useState section). */
дети PROP полезен, если мы хотим пройти элементы/компоненты как реквизиты к другим компонентам.
// Can we accept React elements (or components) as props? // Yes, through a special property on the props object called 'children' function Layout(props) { return{props.children}; } // 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 (); } // different page, but uses same Layout component (thanks to children prop) function AboutPage() { return ( ); }
Опять же, поскольку компоненты являются выражениями JavaScript, мы можем использовать их в сочетании с операторами If-else и выключаниями, чтобы условно показать контент, как это:
function Header() { const isAuthenticated = checkAuth(); /* if user is authenticated, show the authenticated app, otherwise, the unauthenticated app */ if (isAuthenticated) { return} else { /* alternatively, we can drop the else section and provide a simple return, and the conditional will operate in the same way */ return } }
Чтобы использовать условия в возвращенном компонентах jsx компонента, вы можете использовать тройную оператор или короткие замыкания (&& and || операторы).
function Header() { const isAuthenticated = checkAuth(); return ( ); }
Фрагменты являются специальными компонентами для отображения нескольких компонентов без добавления дополнительного элемента до DOM. Они идеально подходят для условной логики, которая имеет несколько соседних компонентов или элементов.
/* We can improve the logic in the previous example. If isAuthenticated is true, how do we display both the AuthenticatedApp and Footer components? */ function Header() { const isAuthenticated = checkAuth(); return ( ); } /* Note: An alternate syntax for fragments is React.Fragment:*/
Списки и ключи
Используйте .map () Функция для преобразования списков данных (массивов) в списки элементов.
const people = ["John", "Bob", "Fred"]; const peopleList = people.map(person =>{person}
);
.map ()
Может использоваться для компонентов, а также простых элементов JSX.
function App() { const people = ['John', 'Bob', 'Fred']; // can interpolate returned list of elements in {} return (
-
{/* we're passing each array element as props to Person */}
{people.map(person =>
This person's name is: {name}
; }Каждый элемент реагирования в списке элементов требуется специальный Ключ опора Отказ Клавиши необходимы для реагирования, чтобы иметь возможность отслеживать каждый элемент, который является итерацией с помощью .map ()
функция.
Реагирование использует клавиши для представления отдельных элементов, когда их данные изменяются (вместо перезарядки всего списка).
Клавиши должны иметь уникальные значения, чтобы иметь возможность идентифицировать каждого из них в соответствии с их ключевым значением.
function App() { const people = [ { id: 'Ksy7py', name: 'John' }, { id: '6eAdl9', name: 'Bob' }, { id: '6eAdl9', name: 'Fred' }, ]; return (
-
{/* keys need to be primitive values, ideally a unique string, such as an id */}
{people.map(person =>
-
{/* use array element index for key */}
{people.map((person, i) =>
Слушатели событий и обработка событий
Прослушивание событий на элементах JSX против HTML-элементах отличается несколькими важными способами.
Во-первых, вы не можете прослушать события на компонентах реагирования – только на элементах JSX. Добавление опоры под названием OnClick
Например, к компоненту реагирования просто будет еще одним свойством, добавленным к объекту реквизита.
/* The convention for most event handler functions is to prefix them with the word 'handle' and then the action they perform (i.e. handleToggleTheme) */ function handleToggleTheme() { // code to toggle app theme } /* In HTML, onclick is all lowercase, plus the event handler includes a set of parentheses after being referenced */ /* In JSX, onClick is camelcase, like attributes / props. We also pass a reference to the function with curly braces. */
Самые важные события реагирования на то, чтобы знать OnClick
, Onchange
и OnsUbmit
Отказ
OnClick
Ручки Нажмите события на элементах JSX (а именно на кнопках)Onchange
обрабатывает события клавиатуры (а именно пользователь, набрав в ввод или текстура)OnsUbmit
Ручки образуют представления от пользователя
function App() { function handleInputChange(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; // text typed into the input const inputName = event.target.name; // 'email' from name attribute } function handleClick(event) { /* onClick doesn't usually need event data, but it receives event data as well that we can use */ console.log('clicked!'); const eventType = event.type; // "click" const eventTarget = event.target; // } function handleSubmit(event) { /* When we hit the return button, the form will be submitted, as well as when a button with type="submit" is clicked. We call event.preventDefault() to prevent the default form behavior from taking place, which is to send an HTTP request and reload the page. */ event.preventDefault(); const formElements = event.target.elements; // access all element within form const inputValue = event.target.elements.emailAddress.value; // access the value of the input element with the id "emailAddress" } return (); }
Основные реактивные крючки
Государство и утилизация
Уместите
Крюк дает нам состояние в функциональном компоненте. Государство Позволяет нам получить доступ и обновлять определенные значения в наших компонентах со временем.
Состояние локального компонента управляется реактивный крюк Уместите
Что дает нам как переменную состояния, так и функцию, которая позволяет нам обновить его.
Когда мы называем Уместите
Мы можем дать нашему государству значение по умолчанию, предоставив его как первый аргумент, когда мы называем Уместите
Отказ
import React from 'react'; /* How do you create a state variable? Syntax: const [stateVariable] = React.useState(defaultValue); */ function App() { const [language] = React.useState('JavaScript'); /* We use array destructuring to declare state variable. Like any variable, we declare we can name it what we like (in this case, 'language'). */ returnI am learning {language}; }
Примечание. Любой крючок в этом разделе находится из библиотеки NACT CORE и может быть импортирован индивидуально.
import React, { useState } from "react"; function App() { const [language] = useState("javascript"); returnI am learning {language}; }
Уместите
Также дает нам функцию «Setter» для обновления состояния после его создания.
function App() { /* The setter function is always the second destructured value. The naming convention for the setter function is to be prefixed with 'set'. */ const [language, setLanguage] = React.useState("javascript"); return ({/* Why use an inline arrow function here instead of immediately calling it like so: onClick={setterFn()}? If so, setLanguage would be called immediately and not when the button was clicked by the user. */}); } /* Note: whenever the setter function is called, the state updates, and the App component re-renders to display the new state. Whenever state is updated, the component will be re-rendered */I am now learning {language}
Уместите
Может использоваться один или несколько раз в пределах одного компонента. И он может принимать примитивные или объектные значения для управления состоянием.
function App() { const [language, setLanguage] = React.useState("python"); const [yearsExperience, setYearsExperience] = React.useState(0); return (setYearsExperience(event.target.value)} />); }I am now learning {language}
I have {yearsExperience} years of experience
Если новое состояние зависит от предыдущего состояния, чтобы гарантировать, что обновление выполняется надежно, мы можем использовать функцию в пределах функции настройки, которая дает нам правильное предыдущее состояние.
/* We have the option to organize state using whatever is the most appropriate data type, according to the data we're managing */ 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 to spread out all of its properties */ setDeveloper({ ...developer, yearsExperience: years }); } return ({/* No need to get previous state here; we are replacing the entire object */} {/* We can also pass a reference to the function */}); }I am now learning {developer.language}
I have {developer.yearsExperience} years of experience
Если вы управляете несколькими примитивными значениями, используя Уместите
Несколько раз часто лучше, чем использовать его один раз с объектом. Вам не нужно беспокоиться о том, чтобы забыть сочетать старое государство с новым государством.
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 ( ); }
Побочные эффекты и использование
Useffect
Давайте выполним побочные эффекты в функциональных компонентах. Так каковы побочные эффекты?
Побочные эффекты где мы должны добраться до внешнего мира. Например, выберите данные из API или работать с DOM.
Это действия, которые могут изменить состояние нашего компонента непредсказуемому моду (которые имеют причину «побочные эффекты»).
Useffect
Принимает функцию обратного вызова (называемая функцией «Effect»), которая по умолчанию будет выполняться каждый раз, когда есть переназначение.
Он запускается после наших компонентных креплений, что является правильным временем для выполнения побочного эффекта в жизненном цикле компонента.
/* What does our code do? Picks a color from the colors array and makes it the background color */ import React, { useState, useEffect } from 'react'; function App() { const [colorIndex, setColorIndex] = 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 handleChangeColor() { /* This code may look complex, but all it does is go to the next color in the 'colors' array, and if it is on the last color, goes back to the beginning */ const nextIndex = colorIndex + 1 === colors.length ? 0 : colorIndex + 1; setColorIndex(nextIndex); } return ( ); }
Чтобы избежать выполнения обратного вызова эффекта после каждого визуализации, мы предоставляем второй аргумент, пустой массив.
function App() { ... /* With an empty array, our button doesn't work no matter how many times we click it... The background color is only set once, when the component first mounts. */ useEffect(() => { document.body.style.backgroundColor = colors[colorIndex]; }, []); /* How do we not have the effect function run for every state update but still have it work whenever the button is clicked? */ return ( ); }
Useffect
Позволяет нам условно выполнять эффекты с массивом зависимостей.
Массив зависимостей Это второй аргумент, и если какой-либо из значений в массиве изменяется, функция эффекта снова работает.
function App() { const [colorIndex, setColorIndex] = React.useState(0); const colors = ["blue", "green", "red", "orange"]; /* Let's add colorIndex to our dependencies array When colorIndex changes, useEffect will execute the effect function 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 ( ); }
Useffect
Давайте отписаться от определенных эффектов, возвращая функцию в конце.
function MouseTracker() { const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }); React.useEffect(() => { // .addEventListener() sets up an active listener... window.addEventListener("mousemove", handleMouseMove); /* ...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", handleMouseMove); }; }, []); function handleMouseMove(event) { setMousePosition({ x: event.pageX, y: event.pageY }); } return (); }The current mouse position is:
X: {mousePosition.x}, Y: {mousePosition.y}
Useffect
Это крючок для использования, когда вы хотите сделать HTTP-запрос (а именно, получить запрос на получение компонентов).
Обратите внимание, что обработка обещаний с более лаконичным синтаксисом Async/await требует создания отдельной функции. (Почему? Функция обратного вызова эффекта не может быть async.)
const endpoint = "https://api.github.com/users/reedbarger"; // Using .then() callback functions to resolve promise function App() { const [user, setUser] = React.useState(null); React.useEffect(() => { fetch(endpoint) .then(response => response.json()) .then(data => setUser(data)); }, []); } // Using async / await syntax to resolve promise: function App() { const [user, setUser] = React.useState(null); // cannot make useEffect callback function async React.useEffect(() => { getUser(); }, []); // We must apply async keyword to a separate function async function getUser() { const response = await fetch(endpoint); const data = await response.json(); setUser(data); } }
Refs и Useref.
Refs являются специальным атрибутом, имеющим доступные на всех компонентах реагирования. Они позволяют нам создать ссылку на данный элемент/компонент, когда компонент монтируется.
УСЭРЕФ
позволяет нам легко использовать React Refs. Мы называем 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 reference an empty object */ const searchInput = useRef(null); function handleClearSearch() { /* .current references the input element upon mount useRef can store basically any value in its .current property */ searchInput.current.value = ""; searchInput.current.focus(); } return (); }
Крючки и производительность
Предотвращение рендеров и реагирования. Мэмо
React.memo
это функция, которая позволяет нам оптимизировать способ отображения наших компонентов.
В частности, он выполняет процесс под названием мемузаризация Это помогает нам предотвратить повторное рендеринг наших компонентов, когда им не нужно делать это (см. RECT.USEMEMO для более полного определения воспоминания).
React.memo
Большинство помогает большинству с предотвращением пересмотренных компонентов компонентов, когда их родительские компоненты повторно визуализируют.
/* In the following application, we are keeping track of our programming skills. We can create new skills using an input, and they are added to the list (shown in the SkillList component). If we click on a skill, it is deleted. */ function App() { const [skill, setSkill] = React.useState('') const [skills, setSkills] = React.useState([ 'HTML', 'CSS', 'JavaScript' ]) function handleChangeInput(event) { setSkill(event.target.value); } function handleAddSkill() { setSkills(skills.concat(skill)) } return ( <>); } /* But the problem, if you run this code yourself, is that when we type into the input, because the parent component of SkillList (App) re-renders, due to the state being updated on every keystroke, the SkillList is rerendered constantly (as indicated by the console.log) */ /* However, once we wrap the SkillList component in React.memo (which is a higher-order function, meaning it accepts a function as an argument), it no longer re-renders unnecessarily when our parent component does. */ const SkillList = React.memo(({ skills }) => { console.log('rerendering'); return (
-
{skills.map((skill, i) =>
- {skill} )}
Функции обратного вызова и USECallback
UseCallback
это крючок, который используется для улучшения производительности нашего компонента. Функции обратного вызова Название функций, которые «называют спиной» внутри родительского компонента.
Наиболее распространенное использование состоит в том, чтобы иметь родительский компонент с переменной состояния, но вы хотите обновить это состояние из дочернего компонента. Что вы делаете? Вы передаете функцию обратного вызова к ребенку от родителя. Это позволяет нам обновлять состояние в родительском компоненте.
UseCallback
функционирует аналогичным образом, как React.memo
Отказ Немечализуют функции обратного вызова, поэтому он не воссоздан на каждом рендере. Использование UseCallback
Правильно может улучшить производительность нашего приложения.
/* Let's keep the exact same App as above with React.memo, but add one small feature. Let's make it possible to delete a skill when we click on it. To do that, we need to filter the skills array according to the skill we click on. For that, we create the handleRemoveSkill function in App */ function App() { const [skill, setSkill] = React.useState('') const [skills, setSkills] = React.useState([ 'HTML', 'CSS', 'JavaScript' ]) function handleChangeInput(event) { setSkill(event.target.value); } function handleAddSkill() { setSkills(skills.concat(skill)) } function handleRemoveSkill(skill) { setSkills(skills.filter(s => s !== skill)) } /* Next, we pass handleRemoveSkill down as a prop, or since this is a function, as a callback function to be used within SkillList */ return ( <>); } /* When we try typing in the input again, we see rerendering in the console every time we type. Our memoization from React.memo is broken! What is happening is the handleRemoveSkill callback function is being recreated everytime App is rerendered, causing all children to be rerendered, too. We need to wrap handleRemoveSkill in useCallback and only have it be recreated when the skill value changes. To fix our app, replace handleRemoveSkill with: const handleRemoveSkill = React.useCallback((skill) => { setSkills(skills.filter(s => s !== skill)) }, [skills]) Try it yourself! */ const SkillList = React.memo(({ skills, handleRemoveSkill }) => { console.log('rerendering'); return (
-
{skills.map(skill =>
- handleRemoveSkill(skill)}>{skill} )}
Мемонизация и упреждающие
Угемер
очень похоже на UseCallback
и предназначен для улучшения производительности. Но вместо того, чтобы быть для обратных вызовов, это для хранения результатов дорогих расчетов
Угемер
позволяет нам Memoize или помните результат дорогих расчетов, когда они уже были сделаны для определенных входов.
Воспоминание означает, что если вычисление было сделано ранее с данным входом, нет необходимости делать это снова, потому что у нас уже есть хранимый результат этой операции.
Угемер
Возвращает значение из вычисления, которое затем сохраняется в переменной.
/* Building upon our skills app, let's add a feature to search through our available skills through an additional search input. We can add this in a component called SearchSkills (shown above our SkillList). */ function App() { const [skill, setSkill] = React.useState('') const [skills, setSkills] = React.useState([ 'HTML', 'CSS', 'JavaScript', ...thousands more items ]) function handleChangeInput(event) { setSkill(event.target.value); } function handleAddSkill() { setSkills(skills.concat(skill)) } const handleRemoveSkill = React.useCallback((skill) => { setSkills(skills.filter(s => s !== skill)) }, [skills]) return ( <>); } /* Let's imagine we have a list of thousands of skills that we want to search through. How do we performantly find and show the skills that match our search term as the user types into the input ? */ function SearchSkills() { const [searchTerm, setSearchTerm] = React.useState(''); /* We use React.useMemo to memoize (remember) the returned value from our search operation and only run when it the searchTerm changes */ const searchResults = React.useMemo(() => { return skills.filter((s) => s.includes(searchTerm); }), [searchTerm]); function handleSearchInput(event) { setSearchTerm(event.target.value); } return ( <>
-
{searchResults.map((result, i) =>
- {result}
Усовершенствованные реактивный крючки
Контекст и упреждающий текст
В реакции мы хотим избежать следующей проблемы создания нескольких реквизитов для передачи данных на два или более уровня из родительского компонента.
/* React Context helps us avoid creating multiple duplicate props. This pattern is also called props drilling. */ /* In this app, we want to pass the user data down to the Header component, but it first needs to go through a Main component which doesn't use it */ function App() { const [user] = React.useState({ name: "Fred" }); return ( // First 'user' prop ); } const Main = ({ user }) => ( <> {/* Second 'user' prop */} Main app content...); const Header = ({ user }) =>Welcome, {user.name}! ;
Контекст полезен для прохождения выбросов нескольких уровней дочерних компонентов из родительского компонента.
/* Here is the previous example rewritten with Context. First we create context, where we can pass in default values We call this 'UserContext' because we're passing down user data */ const UserContext = React.createContext(); function App() { const [user] = React.useState({ name: "Fred" }); return ( {/* We wrap the parent component with the Provider property We pass data down the component tree on the value prop */}); } const Main = () => ( <> Main app content); /* We can't remove the two 'user' props. Instead, we can just use the Consumer property to consume the data where we need it */ const Header = () => ( {/* We use a pattern called render props to get access to the data */}{user => );Welcome, {user.name}! }
упреждающий текст
Крюк позволяет нам потреблять контекст в любом функциональном компоненте, который является ребенком провайдера, а не использует образец рендеринга.
function Header() { /* We pass in the entire context object to consume it and we can remove the Consumer tags */ const user = React.useContext(UserContext); returnWelcome, {user.name}! ; };
Редукторы и упредверс
Редукторы являются простыми, предсказуемыми (чистыми) функциями, которые принимают предыдущий объект состояния и объект действий и возврат нового объекта состояния.
/* This reducer manages user state in our app: */ function userReducer(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, we get data from the payload object on action */ case "LOGIN": return { username: action.payload.username, email: action.payload.email isAuth: true }; case "SIGNOUT": return { username: "", email: "", isAuth: false }; default: /* If no case matches the action received, return the previous state */ return state; } }
Редукторы – это мощный шаблон для управления состоянием, который используется в популярной библиотеке государственных управленческих библиотеков (обычно используется с реакцией).
Редукторы могут быть использованы в реакции с Успеведщик
крючок, чтобы управлять состоянием по нашему приложению, по сравнению с тельцемией (который предназначен для местного компонента).
Успеведщик
можно сопрянуть с упреждающий текст
управлять данными и легко передавать его вокруг компонентов.
Таким образом Успеведщик
+ упреждающий текст
Может быть целая система управления нашими приложениями.
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} ); }
Писать пользовательские крючки
Крючки были созданы для легкого повторного использования поведения между компонентами, аналогичными, как компоненты были созданы для повторного использования структуры в нашем применении.
Крючки позволяют добавлять пользовательские функции в наши приложения, которые соответствуют нашим потребностям и могут быть объединены со всеми существующими крючками, которые мы покрывали.
Крючки также могут быть включены в сторонние библиотеки ради всех разработчиков реагирования. Есть много замечательных библиотек RACT React, которые обеспечивают пользовательские крючки, такие как @ Apollo/Client
, React-Query
, SWR
и больше.
/* Here is a custom React hook called useWindowSize that I wrote in order to calculate the window size (width and height) of any component it is used in */ import React from "react"; export default function useWindowSize() { const isSSR = typeof window !== "undefined"; const [windowSize, setWindowSize] = React.useState({ width: isSSR ? 1200 : window.innerWidth, height: isSSR ? 800 : window.innerHeight, }); function changeWindowSize() { setWindowSize({ width: window.innerWidth, height: window.innerHeight }); } React.useEffect(() => { window.addEventListener("resize", changeWindowSize); return () => { window.removeEventListener("resize", changeWindowSize); }; }, []); return windowSize; } /* To use the hook, we just need to import it where we need, call it, and use the width wherever we want to hide or show certain elements, such as in a Header component. */ // components/Header.js import React from "react"; import useWindowSize from "../utils/useWindowSize"; function Header() { const { width } = useWindowSize(); return ({/* visible only when window greater than 500px */} {width > 500 && ( <> Greater than 500px! )} {/* visible at any window size */}); }I'm always visible
Правила крючков
Существует два основных правила использования реактивных крючков, которые мы не можем нарушать для них работать правильно:
- Крючки могут использоваться только в компонентах функций (не простые функции JavaScript или компоненты класса)
- Крючки могут быть вызваны только в верхней части компонентов (они не могут быть условными, петлями или вложенными функциями)
Заключение
Есть и другие достойные концепции, которые вы можете узнать, но если вы обязуетесь изучить концепции, покрытые в этой ChechSheet, у вас будет отличное понимание самых важных и мощных частей библиотеки Ractive.
Хотите сохранить это руководство для дальнейшего использования?
Загрузите полную версию PDF этой ChechSheet здесь.