Резюме советов по реакции

React.js
Резюме советов по реакции

image.png

введение

использоватьReact.jsЧерез некоторое время я записал подводные камни и хитрости, с которыми столкнулся в процессе использования, надеясь помочь другим. Эта статья — длинная история, вы можете расти, только если сможете выдержать одиночество и искушение.

image.png

1. Инструменты

1. Показать html

<div dangerouslySetInnerHTML={{ __html: LANG.auth_register_tips1 }}/>

2. Общие компоненты

  • axios(httpМодуль запроса, который можно использовать в любом интерфейсном сценарии, очень мощный)
  • echarts-for-react(Достаточно визуальных диаграмм, других инкапсуляций диаграмм на основе реакции)
  • recharts(еще один на основеreactупакованная схема)
  • nprogress(верхняя полоса загрузки, работает нормально)
  • react-draft-wysiwyg(другие на основеreactпакет rich text, если найдёте что-то лучше, то сможете заменить)
  • react-draggable(Перетащите модуль, нашел простую версию)
  • screenfull(полноэкранный плагин)
  • photoswipe(Плагин всплывающего окна с изображением, не зависит от jQuery, но по-прежнему очень прост в использовании)
  • animate.css(библиотека css-анимации)
  • redux WebПриложение представляет собой конечный автомат, а представление и состояние находятся во взаимно однозначном соответствии, все состояния хранятся в объекте
  • redux-loggerжурнал
  • Reselectкомпонент памяти
  • redux-thunk Для решения проблемы асинхронного действия
  • redux-sagaДля решения проблемы асинхронного действия
  • react-router-redux Поддерживайте синхронизацию маршрутов с состоянием приложения
  • react-router-dom

3, Инструменты отладки React-devtools

Адрес инструмента:GitHub.com/Facebook/Горячие…

Установить глобально:

yarn global add react-devtools

Конфигурация: Настройте его в package.json:

"scripts": {
"devtools": "react-devtools"
}

Затем вы можете начать: пряжа запустить devtools

image.png

2. Коммуникация компонентов

Несколько ситуаций, требующих связи между компонентами

  • Родительский компонент связывается с дочерним компонентом
  • Дочерний компонент взаимодействует с родительским компонентом
  • Взаимодействие компонентов между уровнями
  • Связь между компонентами без вложенных отношений
  1. редукционная архитектура
  2. Родительский компонент для дочернего компонента - реквизит
  3. Дочерний компонент получает параметры от родительского компонента - props.funciton
  4. Используйте механизм событий

1. Родительский компонент взаимодействует с дочерним компонентом

Поток данных React является односторонним, и связь между родительскими компонентами и дочерними также является наиболее распространенной; родительские компоненты передают необходимую информацию дочерним компонентам через реквизиты.

2. Дочерний компонент взаимодействует с родительским компонентом

  • Используйте функции обратного вызова
  • Используйте собственный механизм событий

Вложенные элементы изменяют состояние родительского компонента.

// 一般改变state值的一种方式
const { data } = this.state;
this.setState({ data: {...data, key: 1 } });
// 另外一种可以通过callback的方式改变state的值
this.setState(({ data }) => ({ data: {...data, key: 1 } }));
// 还可以
this.setState((state, props) => {
return { counter: state.counter + props.step };
});

3. Межуровневая коммуникация компонентов

  • Послойные компоненты передают свойства
Например, для связи между компонентом A и компонентом B сначала найдите общий родительский компонент A и B, сначала свяжитесь с компонентом C, а компонент C взаимодействует с компонентом B через реквизиты.В это время компонент C играет роль промежуточного программного обеспечения.
  • использовать контекст
Контекст — это глобальная переменная, как большой контейнер, к которому можно получить доступ где угодно, мы можем поместить информацию для передачи в контекст, а затем свободно получить ее в других компонентах; но React официально не рекомендует использовать большое количество контекстов, хотя это может уменьшить послойную передачу, но когда структура компонента сложная, мы не знаем, откуда передается контекст; а контекст — это глобальная переменная, а глобальная переменная — виновник, который вызывает приложение стать хаотичным.

использовать контекст

Связь компонентов в следующем примере: ListItem — дочерний компонент List, List — дочерний компонент приложения.

ListItem.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
class ListItem extends Component {
    // 子组件声明自己要使用context
    static contextTypes = {
        color: PropTypes.string,
    }
    static propTypes = {
        value: PropTypes.string,
    }
    render() {
        const { value } = this.props;
        return (
            <li style={{ background: this.context.color }}>
                <span>{value}</span>
            </li>
        );
    }
}
export default ListItem;

List.js

import ListItem from './ListItem';
class List extends Component {
    // 父组件声明自己支持context
    static childContextTypes = {
        color: PropTypes.string,
    }
    static propTypes = {
        list: PropTypes.array,
    }
    // 提供一个函数,用来返回相应的context对象
    getChildContext() {
        return {
            color: 'red',
        };
    }
    render() {
        const { list } = this.props;
        return (
            <div>
                <ul>
                    {
                        list.map((entry, index) =>
                            <ListItem key={`list-${index}`} value={entry.text} />,
                       )
                    }
                </ul>
            </div>
        );
    }
}
export default List;

App.js

import React, { Component } from 'react';
import List from './components/List';
const list = [
    {
        text: '题目一',
    },
    {
        text: '题目二',
    },
];
export default class App extends Component {
    render() {
        return (
            <div>
                <List
                    list={list}
                />
            </div>
        );
    }
}

4. Взаимодействие компонентов без вложенности

  • Использовать собственный механизм событий
В событии componentDidMount, если компонент смонтирован, снова подпишитесь на событие; когда компонент размонтируется, отмените подписку на событие в событии componentWillUnmount; возьмите в качестве примера обычный режим публикации/подписки, позаимствовайте браузерную версию Node. Модуль событий .js для достижения

Как использовать пользовательские события

Отношения компонентов в следующем примере: List1 и List2 не имеют отношения вложенности, а App является их родительским компонентом;

Реализуйте такую ​​функцию: нажмите кнопку в List2, чтобы изменить отображение информации в List1.

Во-первых, вам нужно установить пакет событий в проект:

npm install events --save

Создайте файл events.js в новом каталоге util в разделе src.

import { EventEmitter } from 'events';
export default new EventEmitter();

list1.js

import React, { Component } from 'react';
import emitter from '../util/events';
class List extends Component {
    constructor(props) {
        super(props);
        this.state = {
            message: 'List1',
        };
    }
    componentDidMount() {
        // 组件装载完成以后声明一个自定义事件
        this.eventEmitter = emitter.addListener('changeMessage', (message) => {
            this.setState({
                message,
            });
        });
    }
    componentWillUnmount() {
        emitter.removeListener(this.eventEmitter);
    }
    render() {
        return (
            <div>
                {this.state.message}
            </div>
        );
    }
}
export default List;

List2.js

import React, { Component } from 'react';
import emitter from '../util/events';
class List2 extends Component {
    handleClick = (message) => {
        emitter.emit('changeMessage', message);
    };
    render() {
        return (
            <div>
                <button onClick={this.handleClick.bind(this, 'List2')}>点击我改变List1组件中显示信息</button>
            </div>
        );
    }
}

APP.js

import React, { Component } from 'react';
import List1 from './components/List1';
import List2 from './components/List2';
export default class App extends Component {
    render() {
        return (
            <div>
                <List1 />
                <List2 />
            </div>
        );
    }
}

Пользовательские события — это типичная модель публикации-подписки, которая реализует связь между компонентами путем добавления слушателей к объектам событий и запуска событий.

Метод onRef для связи между компонентами

Межкомпонентная коммуникация в дополнение кpropsв дополнение кonRefметод, но официальная документация React не рекомендует чрезмерно полагаться на ref. В этой статье используетсяonRefКонтекст заключается в извлечении общедоступных компонентов при вводе формы и получении сведений о форме при отправке.

Нажмите кнопку родительского компонента в приведенной ниже демонстрации, чтобы получить всю информацию о дочернем компоненте, включая статус и метод, вы можете увидеть печать консоли в демонстрации.

// 父组件
class Parent extends React.Component {
  testRef=(ref)=>{
    this.child = ref
    console.log(ref) // -> 获取整个Child元素
  }
  handleClick=()=>{
    alert(this.child.state.info) // -> 通过this.child可以拿到child所有状态和方法
  }
  render() {
    return <div>
      <Child onRef={this.testRef} />
      <button onClick={this.handleClick}>父组件按钮</button>
    </div>
  }
}
// 子组件
class Child extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      info:'快点击子组件按钮哈哈哈'
    }
  }
  componentDidMount(){
    this.props.onRef(this)
    console.log(this) // ->将child传递给this.props.onRef()方法
  }
  handleChildClick=()=>{
    this.setState({info:'通过父组件按钮获取到子组件信息啦啦啦'})
  } 
  render(){
    return <button onClick={this.handleChildClick}>子组件按钮</button>
  }
}
принцип:

Когда функция onRef вызывается в дочернем компоненте, вызывается функция, переданная из родительского компонента.this.props.onRef(this)Здесь параметр указывает на сам дочерний компонент, а родительский компонент получает эту ссылку в качестве первого параметра:onRef = {ref =>(this.child = ref)}затем он используетthis.childСохраните ссылку.После этого можно получить доступ ко всему экземпляру дочернего компонента в родительском компоненте и вызвать функции дочернего компонента.

3. Маршрутизация

Для одностраничных приложений, созданных с помощью React, если вы хотите переходить между страницами, первое, что вам приходит в голову, — это использовать маршрутизацию. В React для выполнения этого требования обычно используются два пакета: react-router и react-router-dom. В этой статье в основном описывается react-router-dom.

image.png

1. В React Router есть три типа компонентов:

  • routerКомпоненты (BrowserRouter, HashRouter)
  • route matchingКомпоненты (маршрут, коммутатор)
  • navigationКомпоненты (ссылка)

Для веб-приложений на основе React Router корневой компонент должен быть компонентом маршрутизатора (BrowserRouter,HashRouter). в проекте,react-router-domПредусмотрено и два маршрута. Оба маршрута создадутhistoryобъект. Если в нашем приложении есть сервер, который отвечает на веб-запросы, мы обычно используем<BrowserRouter>компонент; при использовании статического файлового сервера мы должны использовать<HashRouter>компоненты

2. HashRouter и BrowserRouter

По сути, это режимы хэширования и истории маршрутизации (если вы не понимаете разницу между этими двумя режимами, вам нужно это восполнить)

И эти два компонента являются контейнером маршрута и должны находиться в самом внешнем слое.

// hash模式
ReactDom.render(
  <HashRouter>
        <Route path="/" component={Home}/>
    </HashRouter>
)
// history模式
ReactDom.render(
  <BrowserRouter>
        <Route path="/" component={Home}/>
    </BrowserRouter>
)

Поговорим о параметрах HashRouter и BrowserRouter.

  • Базовая ссылка маршрута basename используется для развертывания в некорневой каталог. Например, если вам нужно развернуть проект на www.xxxx.com/web, установите basename="/web"
  • getUserConfirmation используется для перехвата компонента Prompt и принятия решения о переходе
  • forceRefresh используется для установки принудительного обновления всего браузера, значение по умолчанию — false
  • keLength используется для установки длины location.key, по умолчанию 6, которую можно настроить

3. Маршрут

Маршрут - это исходный материал для маршрутизации, это компонент, который управляет отображением, соответствующим маршруту.

Параметры маршрута

  • дорожка прыжка дорожка
  • компонент соответствует компоненту, отображаемому путем
  • Рендер может написать свою собственную функцию рендеринга, чтобы вернуть конкретный дом без установки компонента.
  • location передает объект маршрута, сравнивает его с текущим объектом маршрута и переходит, если он совпадает
  • Точные соответствует правилу, когда true, он точно совпадает.
path url Открыть ли результат матча
/a /a/b false yes
/a /a/b true no
  • чувствительный Является ли путь чувствительным к регистру
path url Открыть ли результат матча
/a /a true yes
/a /A true yes
  • Соответствует ли strict следующему /
path url Открыть ли результат матча
/a /a/ true yes
/a /a/c true yes
/a /a true no

4. Маршрутизатор

Низкоуровневая маршрутизация, подходящая для любого компонента маршрутизации, в основном глубоко интегрированного с избыточностью, должна использоваться с объектом истории.

Целью использования маршрутизации маршрутизатора является синхронизация с библиотекой управления состоянием, такой как история в редуксе.

<Router history={history}>
    ...
</Router>

5. Ссылка и NavLink

Оба являются прыжковыми маршрутами, и NavLink имеет больше параметров.

API ссылки

  • Существует два способа записи, указывающих, по какому маршруту перейти.
  • Строковая запись
<Link to="/a"/>
  • Обозначение объекта
<Link to={{
  pathname: '/courses',
  search: '?sort=name',
  hash: '#the-hash',
  state: { fromDashboard: true }
}}/>
  • заменить, чтобы изменить нажмите, чтобы заменить
  • innerRef обращается к dom тега Link

API NavLink

  • Все API ссылки
  • activeClassName Имя класса, установленное при активации маршрута.
  • стиль настройки активации маршрута activeStyle
  • точная ссылка Маршрут, активный класс будет активирован только при выполнении этого условия
  • strict относятся к Route, активный класс будет активирован только при выполнении этого условия
  • isActive получает callback-функцию, которая срабатывает при изменении активного состояния и прерывает прыжок, если возвращает false
const oddEvent = (match, location) => {
  console.log(match,location)
  if (!match) {
    return false
  }
  console.log(match.id)
  return true
}
<NavLink isActive={oddEvent} to="/a/123">组件一</NavLink>
  • location получает объект местоположения, и он будет переходить, когда URL-адрес удовлетворяет условиям этого объекта.
<NavLink to="/a/123" location={{ key:"mb5wu3", pathname:"/a/123" }}/>

6, перенаправление

Перенаправление очень простое, мы можем видеть код напрямую

// 基本的重定向
<Redirect to="/somewhere/else" />
// 对象形式
<Redirect
  to={{
    pathname: "/login",
    search: "?utm=your+face",
    state: { referrer: currentLocation }
  }}
/>
// 采用push生成新的记录
<Redirect push to="/somewhere/else" />
// 配合Switch组件使用,form表示重定向之前的路径,如果匹配则重定向,不匹配则不重定向
<Switch>
  <Redirect from='/old-path' to='/new-path'/>
  <Route path='/new-path' component={Place}/>
</Switch>

7. Переключатель

Переключение маршрута будет соответствовать только первому маршруту, который можно представить в виде панели вкладок.

Switch может содержать только Route, Redirect и Router

<Switch>
  <Route exact path="/" component={Home}/>
  <Route path="/about" component={About}/>
  <Route path="/:user" component={User}/>
  <Route component={NoMatch}/>
</Switch>

8. с роутером

Когда немаршрутизирующий компонент также хочет получить доступ к объектам сопоставления, местоположения и истории текущего маршрута, тогда withRouter будет очень хорошим выбором, который можно понимать как обертывание компонента в компонент маршрутизации.

import { withRouter } from 'react-router-dom'
const MyComponent = (props) => {
    const { match, location, history } = this.props
     return (
        <div>{props.location.pathname}</div>
    )
}
const FirstTest = withRouter(MyComponent);

9. Объект истории

Любой, кто использовал vue, знает, что vue-router имеет навигацию по компонентам и программную навигацию.Как react-router использует API для управления вперед, назад и обновлением? Это требует от нас объяснения роли объекта истории.

Фактически, в каждом компоненте маршрутизации мы можем использовать this.props.history, чтобы получить объект истории, или мы можем использовать withRouter, чтобы обернуть компонент, чтобы получить его.

Методы push, replace, go и другие инкапсулированы в историю, детали таковы:

History {
    length: number;
    action: Action;
    location: Location;
    push(path: Path, state?: LocationState): void; // 调用push前进到一个地址,可以接受一个state对象,就是自定义的路由数据
    push(location: LocationDescriptorObject): void; // 接受一个location的描述对象
    replace(path: Path, state?: LocationState): void; // 用页面替换当前的路径,不可再goBack
    replace(location: LocationDescriptorObject): void; // 同上
    go(n: number): void; // 往前走多少也页面
    goBack(): void; // 返回一个页面
    goForward(): void; // 前进一个页面
    block(prompt?: boolean | string | TransitionPromptHook): UnregisterCallback;
    listen(listener: LocationListener): UnregisterCallback;
    createHref(location: LocationDescriptorObject): Href;
}

Таким образом, если мы хотим использовать API для работы вперед и назад, мы можем вызывать методы в истории.

Во-вторых, вы также можете потемнетьhistoryбиблиотека для достижения, конкретные случаи следующие

import { BrowserRouter } from 'react-router-dom';
const history = require('history').createBrowserHistory();
/**
 * forceRefresh: bool
 * 作用:当浏览器不支持 HTML5 的 history API 时强制刷新页面。
 */
const supportsHistory = 'pushState' in window.history;
 <BrowserRouter
        history={history}
        basename="/"
        forceRefresh={!supportsHistory}
      >
        {/* 路由入口 */}
       ......
</BrowserRouter>

10. Аутентификация маршрутизации

4. Статьи о производительности

писал некоторое времяreactПосле этого я постепенно влюбился в его использованиеreactписать приложения.

мы знаем,Facebookпри запускеreactОдним из флагов, разыгранных в то время, была высокая производительность.

Сегодня мы все еще говорим вместеreactоптимизация производительности, подумайте, какие еще средства можно использовать для повышения производительности React, чтобы нашаreactБыстрее и лучше производительность.

1. Оптимизация производительности реагирующих компонентов (оптимизация угла рендеринга)

1. Инструмент просмотра производительности React

Прежде чем говорить об оптимизации производительности, нам нужно сначала понять, как просматриватьreactИнструмент для времени, необходимого для загрузки компонентов, прежде чем реагировать на версию 16, которую мы можем использоватьReact Perfпроверить.

react16версия, мы можем использоватьreact-addons-perfинструмент для просмотра, а в последней версии 16 нам нужно только добавить ?react_pref после URL-адреса.

Сначала давайте узнаемreact-addons-perf.

react-addons-perfЭто набор инструментов для повышения производительности, официально запущенный React, который может распечатывать время, время, потерянное время и т. д. рендеринга компонентов.

Кратко расскажите о нескольких API, пожалуйста, обратитесь к конкретному использованиюОфициальный сайт:

  • Perf.start()начать запись
  • Perf.stop()конец записи
  • Perf.printInclusive() Просмотреть визуализацию всех спроектированных компонентов
  • Perf.printWasted() Просмотр рендеринга нежелательных компонентов отходов

Вы можете сначала установить расширение React Perf в chorme, затем в файл входа илиreduxизstore.jsБыл добавлен подходящий код:

image.png

Давайте посмотрим. В последней версии React16 добавьте ? после URLreact_pref, вы можете использовать браузер Chromeperformance, мы можем просмотретьUser Timeingчтобы увидеть время загрузки компонента. Нажмите запись, чтобы начать запись, обратите внимание, что время записи не должно превышать 20 секунд, иначе это может привести к зависанию Chrome.

image.png

Конкретную операцию использования этого инструмента можно увидеть ниже:

image.png

2. Оптимизация производительности одного компонента реакции

1. Минимизируйте новые переменные и функции связывания в рендере. Параметры - минимизировать количество прошедших параметров.

Во-первых, давайте подумаем о проблеме. Например, я хочу реализовать кнопку щелчка, чтобы сделать соответствующийnumУвеличьте 1, какие методы у нас есть.

Каждый должен уметь придумать не более трех, как показано ниже:

image.png


Первый - привязать в конструктореthis, вторая вrender()Привязка в функцииthis, в-третьих, использовать функции стрелок, которые могут достичь вышеуказанных методов;

Но какой метод имеет наилучшую производительность, это вопрос, который мы должны рассмотреть. Ответ должен знать каждый:У первого лучшая производительность.

Из-за первого конструктор будет выполняться только один раз при каждом рендеринге;

И второй способ, каждый разrender()Когда функция выполняется снова;

Для третьего метода каждый разrender(), будет сгенерирована новая стрелочная функция, даже если содержимое двух стрелочных функций одинаково.

Третий способ мы можем привести в пример, т.к.reactопределить, необходимо лиrenderдаповерхностное сравнение, просто по===Судить, еслиstateилиpropТипом является строка или число, пока значения одинаковы, поверхностное сравнение будет считать их одинаковыми;

Но если тип первого является сложным объектом, мы знаем, что объект является ссылочным типом, и поверхностное сравнение будет рассматривать только эти два типа.propЯвляется ли это одной и той же ссылкой, если нет, даже если содержимое двух объектов точно такое же, они будут считаться двумя разнымиprop.

Например:

Когда мы даем компонентFooдай имяstyleизpropназначать;

<Foo style={{ color:"red" }}

Используя этот метод, каждый рендер считаетсяstyleэтоpropизменилось, потому что каждый раз, когда объект создается дляstyle.

Так как же нам улучшить, если мы хотим сделатьreactПри рендеринге учитывайте тип объекта до и послеpropто же, это должно быть обеспеченоpropуказать на то жеjavascriptобъекта следующим образом:

const fooStyle = { color: "red" }; //取保这个初始化只执行一次,不要放在render中,可以放在构造函数中

<Foo style={fooStyle} />

2. Настройте функцию shouldComponentUpdate

shouldComponentUpdateэто решитьreactКогда компонент не может повторно отобразить функцию, но реализация этой функции по умолчанию состоит в том, чтобы просто вернутьtrue. То есть по умолчанию используемая функция жизненного цикла вызывается каждый раз при ее обновлении, включаяrenderфункция, повторный рендеринг.

Давайте посмотрим на пример ниже

image.png

Мы пишем два компонента,Appа такжеDemoкомпонент и напишите два метода, один для измененияAppсерединаnumзначение, нужно изменитьtitle, мы печатаем функцию рендеринга в рендере демо. Мы можем наблюдать следующие эффекты:

image.png

Мы ясно видим, что хотяdemoв компонентеtitleСтоимость не изменилась, но все жеrender.

Чтобы решить эту проблему, мы можем изменить демонстрационный компонент следующим образом:

image.png

Только когда значение заголовка демо изменится, мы переходим к рендерингу, мы можем посмотреть на эффект:

image.png

Вышеупомянутое является просто особенно простым дляshouldComponentUpdateнастройка.

в последнемreact, реакция дает намReact.PureComponent, чиновник также предоставил раннееreact-addons-pure-render-mixinПлагин для повторной реализацииshouldComponentUpdateМетоды жизненного цикла.

image.png

Эффект вышеуказанного метода также настраивается с намиshouldComponentUpdateЭффект тот же.

Но мы должны отметить, что здесьPureRenderявляются поверхностными сравнениями, потому что сцены глубокого сравнения довольно дороги. Поэтому мы должны заметить, что мы1.1Некоторые примечания, упомянутые в:Не устанавливайте объекты или массивы напрямую для реквизита.,Не привязывайте методы непосредственно к элементам, потому что функции также являются объектами.

3. Оптимизация производительности нескольких компонентов реакции, ключевая оптимизация

reactВ процессе загрузки компонентаreactвrenderМетод генерирует древовидную структуру в памяти, а узлы дерева представляютreactкомпонент или роднойDomЭлемент, это то, что мы называем деревомVitural Dom, реагировать на это, чтобы отобразитьDomДерево.

reactНа этапе обновления по сравнению с оригиналомVitural Domи вновь созданныйVitural Dom, найдите разницу и по-другому визуализируйте дерево Dom.

Чтобы добиться высокой производительности, React принимает временную сложностьO(N)Чтобы сравнить разницу между двумя структурами атрибутов, потому что для точного сравнения двух древовидных структур вам нужно передатьO(N^3), что снижает производительность.

Проще говоря,React использует ключ для идентификации компонентов, который является идентификатором личности., точно так же, как наши удостоверения личности используются для идентификации человека.

ключ списка

  • Ключ не будет передан компоненту.Если вам нужно использовать значение ключа, назовите его как другие свойства и передайте в
  • Когда последовательность списка переупорядочивается, она не подходит для индекса массива в качестве ключа.

* Примечание: есть еще один способ: рекомендуетсяshortidСоздайте массив уникальных ключей и используйте его с массивом данных, избавляя от необходимости реорганизации массива при отправке данных.

Случай:

import React from 'react';
import shortid from 'shortid';

class Demo extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
      data: ['a', 'b', 'c']
    }
    this.dataKeys = this.state.data.map(v => shortid.generate());
  }
  
    deleteOne = index => { // 删除操作
        const { data } = this.state;
        this.setState({ data: data.filter((v, i) => i !== index) });
        this.dataKyes.splice(index, 1);
    }
    
    render() {
      return (
          <ul>
               {
                   data.map((v, i) => 
                    <li 
                        onClick={i => this.deleteOne(i)}  
                        key={this.dataKeys[i]}
                    >
                        {v}
                    </li>
                    )
               } 
            </ul>
      )
  }
}
// 稍微抽取,可以封装一个通用的组件

Также необходимо указать:

Ключ не используется для повышения производительности реакции, но для производительности полезно использовать ключ правильно.

Невозможно использовать случайный ключ для использования

тот же ключ, если свойства компонента изменяются, реакция будет обновлять только свойства, соответствующие компоненту; если изменений нет, он не будет обновляться.

разные ключевые значения, затем react сначала уничтожает компонент (компонент с отслеживанием состоянияcomponentWillUnmount会执行), затем заново создайте компонент (компонент с отслеживанием состоянияconstructorа такжеcomponentWillUnmountбудет казнен)

Приведем несколько ситуаций, которые вы поймете сразу:

  • различные типы узлов
// A组件

<div>
  <Todos />
</div>

// B组件
<span>
  <Todos />
</span>

мы хотим поставитьAКомпоненты обновлены доBкомпоненты,reactПри сравнении обнаруживается, что самый внешний корневой узел отличается, а предыдущий упраздняется напрямую.<div>узел, включая дочерние узлы внутри, это огромная трата, но чтобы избежатьO(N^3)Временная сложность , может быть использована только таким образом
Поэтому в процессе разработки мы должны стараться избегать вышеописанной ситуации и не менять самовольно тип обернутого узла.

  • Оба узла одного типа

Здесь есть два случая, один из которых состоит в том, что узелDomтип, аreactкомпоненты.

дляdomТипа, давайте на примере:

// A组件
<div style={{color: 'red',fontSize:15}} className="welcome">
  Hello World!!!
</div>

// B组件
<div style={{color: 'green',fontSize:15}} className="react">
  Good Bye!!!
</div>

Разница между вышеуказанными компонентами A и B является текстом,className,styleсерединаcolorизмениться, потому чтоDomЭлемент не изменился,ReactБудут изменены только измененные части.

противreactТип компонента, рендеринг — это не что иное, как прохождение процесса обновления экземпляров компонентов, самое главное — настройка.shouldComponentUpdate, мы также упоминали выше, поэтому я не буду вдаваться в подробности.

  • Несколько случаев подкомпонента

Давайте посмотрим два примера

Пример первый:

// A
<ul>
  <TodoItem text="First" complete={false} />
  <TodoItem text="Second" complete={false} />
</ul>

// B
<ul>
  <TodoItem text="First" complete={false} />
  <TodoItem text="Second" complete={false} />
  <TodoItem text="Third" complete={false} />
</ul>

Изменено с A на B, еслиshouldComponentUpdateПравильно обрабатываются, нам просто нужно обновить креплениеthirdэтооднаждыПросто сделай это.

Давайте посмотрим на следующий пример:

// A
<ul>
  <TodoItem text="First" complete={false} />
  <TodoItem text="Second" complete={false} />
</ul>

// B
<ul>
  <TodoItem text="Zero" complete={false} />
  <TodoItem text="First" complete={false} />
  <TodoItem text="Second" complete={false} />
</ul>

Здесь, поскольку реакция принимает временную сложность O (n), она изменит текст как первый на ноль, текст как второй на первый и добавит компонент в конце, текст как второй. Свойства двух существующих текстов были изменены, поэтому они будут отображаться последовательно.

Если у нас здесь 1000 экземпляров, то произойдет 1000 обновлений.

Здесь мы будем использоватьKeyохватывать

Проще говоря, фактически этот ключ является идентификационным номером компонента реакции.

Мы можем избежать вышеупомянутой проблемы, изменив предыдущий пример на следующий, и реакция может знать, что второй и третий компоненты в B на самом деле являются первым и вторым экземплярами в A.

// A
<ul>
  <TodoItem key={1} text="First" complete={false} />
  <TodoItem key={2} text="Second" complete={false} />
</ul>

// B
<ul>
  <TodoItem key={0} text="Zero" complete={false} />
  <TodoItem key={1} text="First" complete={false} />
  <TodoItem key={2} text="Second" complete={false} />
</ul>

Но теперь react также напомнит нам не забывать использоватьkey, если его не добавить, в браузере будет выдано сообщение об ошибке.

image.pngоkeyМы должны обратить внимание на то, чтобы использование этого ключевого значения было стабильным, как иидентификационный номерОн у нас такой же, как стабильный.

Распространенной ошибкой является использование индексного значения массива в качестве ключа, что очень опасно, код следующий, этого надо избегать.

<ul>
  {
        todos.map((item, index) => {
            <TodoItem
              key={index}
              text={item.text}
              completed={item.completed}
        })
  }
</ul>

2. Оптимизация производительности Redux: повторный выбор (оптимизация во время сбора данных)

mapStateToProps также называется селектором, и он вызывается при изменении хранилища, независимо от того, изменяются ли данные, которые селектор заботит, он будет вызываться, поэтому, если селектор требует больших вычислительных ресурсов, пересчет каждого обновления может привести к проблемам с производительностью.

Повторный выбор может помочь вам избежать этих ненужных перерасчетов.

Reselect предоставляет функцию createSelector для создания запоминаемых селекторов.

createSelector принимает в качестве параметров массив селекторов ввода и функцию преобразования.

Если изменение дерева состояний приведет к изменению значения селектора ввода, селектор вызовет функцию преобразования, передаст селекторы ввода в качестве параметра и вернет результат.

Если значение селекторов ввода такое же, как и предыдущее, он будет напрямую возвращать данные из предыдущего вычисления без повторного вызова функции преобразования.

Это позволяет избежать ненужных вычислений и повысить производительность.

пример:

import {} from 'reselect';
export const getItems = (state) => state.cart.get('items');
export const getItemsWithTotals = createSelector(
[ getItems ],
(item) => {
 return items.map(i =>{
  return i.set('total', i.get('price', 0) * i.get('quantity');
 });
}
)

Создайте запоминающийся селектор.Это означает, что getItemWithTotals будет оцениваться при первом запуске функции.

Если та же функция вызывается снова, но входное значение (значение getItems) не изменилось, функция вернет кэшированный результат вычисления.

Если элементы изменены (например: добавлен элемент, изменен номер, что-либо манипулирует результатом getItems), функция будет выполняться снова.

В предыдущем процессе оптимизации мы оптимизировали рендеринг для повышения производительности, посколькуreactа такжеreduxПроцесс рендеринга управляется данными, поэтому процесс оптимизации процесса рендеринга и получения данных также является моментом оптимизации, который необходимо учитывать.

//下面是redux中简单的一个筛选功能
const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_ALL':
      return todos
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
  }
}

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

mapStateToPropsфункционировать какredux storeважная часть получения данных вfilterа такжеtodosЧтобы отобразить соответствующие элементы списка дел, нам нужно пройтиtodosМассив на поле.

Когда массив относительно велик, это снижает производительность.

В это время появился реселект, принцип его действия:Пока соответствующее состояние не изменилось, напрямую используется последний кэшированный результат.

Я не буду вводить больше здесь. Есть много написанных сопутствующих сопутствующих статей. Мне не повторяются. Если вы хотите знать в глубине, вы можете обратиться к нему.повторно выбрать github,Промежуточное ПО для Redux — повторно выбрать.

3. Код разделения

1. Динамическая загрузка

Стандарт ES6 вводит импорт для облегчения нашего модуля статической загрузки. Такие формы, как:

import xxx from xxx.js

Хотя импорт полезен для загрузки модулей, статическая загрузка модулей определенным образом ограничивает нашу способность реализовывать степень загрузки асинхронных модулей. Тем не менее, синтаксис импорта динамически загружаемых модулей () был на стадии предложения, и он ввел и использование веб-пакета. import() предоставляется на Promise API, поэтому import() возвращает значение объекта в завершенном состоянии Promise или в состоянии отклонения. В виде:

import(/* webpackChunkName: 'module'*/ "module")
    .then(() => {
        //todo
    })
    .catch(_ => console.log('It is an error'))

Когда веб-пакет скомпилирован, он распознает синтаксис импорта динамической загрузки, и веб-пакет создаст отдельный пакет для текущего динамически загружаемого модуля. Если вы используете официальную структуру Create-react-app или серверную среду рендеринга React Next.js, вы можете напрямую использовать синтаксис динамического импорта. Если ваш скаффолдинг сконфигурирован самостоятельно через веб-пакет, вам необходимо следовать официальному руководству по его настройке, перейдите к [1].

2. Динамически загружать компоненты React

Одним из самых популярных методов является использованиеReact-loadable[2] Компоненты React с отложенной загрузкой, предоставляемые библиотекой. Он использует синтаксис import() для загрузки компонентов React с использованием синтаксиса Promise. В то же время React-loadable поддерживает рендеринг React на стороне сервера. Обычно мы реализуем компоненты следующим образом:

import LazyComponet from 'LazyComponent';
export default function DemoComponent() {
    return (
        <div>
            <p>demo component</p>
            <AComponent />
        </div>
    )
}

В приведенном выше примере предположимLazyComponetсуществуетDemoComponentМы не показываем это при рендеринге. Но поскольку мы используем синтаксис импорта дляLazyComponetимпортировать, поэтому во время компиляции он будетLazyComponetкод сDemoComponentКод упакован в тот же пакет. Однако это не то, чего мы хотим. Итак, мы можем сделать это, используяReact-loadableленивая загрузкаLazyComponet, в то время какLazyComponetКод упакован отдельно в бандл. Мы можем посмотреть на примеры, представленные на официальном сайте:

import Loadable from 'react-loadable';
import Loading from './my-loading-component';
const LoadableComponent = Loadable({
  loader: () => import('./my-component'),
  loading: Loading,
});
export default class App extends React.Component {
  render() {
    return <LoadableComponent/>;
  }
}

Как видно из примера, нажав реагирование, использует метод динамического импорта () и назначает импортируемый компонент в свойство Loader. В то же время, загружаемый ract, предоставляет свойство загрузки для установки компонента, который будет отображаться при нагрузке компонента.

3. Использование лени и неизвестности

React.lazy and Suspense is not yet available for server-side rendering. If you want to do code-splitting in a server rendered app, we recommend Loadable Components. It has a nice guide for bundle splitting with server-side rendering.


Прежде чем использовать его, нам нужно обратить особое внимание на то, что React официально его поддерживает, React.lazy и Suspense не поддерживают рендеринг на стороне сервера. Поэтому учащиеся, использующие рендеринг на стороне сервера, могут обратиться кreact-loadableа такжеloadable-components[3].

Поскольку я обновляю исходный проект, следующее содержание этой статьи в основном направлено на работу, проделанную старым проектом по обновлению последней версии React.

1. Обновление кода до последней версии React

Если ваш код — Reactv16, вы можете обновить его до последней версии напрямую.Конечно, React16.6 уже предоставляет ленивый и приостановочный методы. Если это версия до версии 16, выполните официальную операцию по миграции.

2. Определите компоненты ленивой загрузки исходного кода

Прежде всего, согласно требованиям, компоненты, загружаемые ниже сгиба, определяются как компоненты с отложенной загрузкой, в моем проекте всего пять компонентов могут быть загружены с отложенной загрузкой. Метод модификации очень прост, оригинальный способ введения компонентов:

import LazyComponent from "../components/LazyComponent ";

изменить на:

const LazyComponent = React.lazy(() =>
  import(/* webpackChunkName: 'lazyComponent'*/ "../components/LazyComponent")
);

Как показано в коде: замените код, который статически ссылается на компонент, на вызов React.lazy(), передайте анонимную функцию в качестве параметра в lazy() и динамически введите ее в функцию.lazyComponentкомпоненты. Таким образом, браузер не загрузит компонент, пока мы его не отобразим.lazyComponent.bundle.jsфайл и его зависимости. Среди них webpackChunkName в импорте — это имя файла пакета, которое мы определили.

Что произойдет, если код, от которого зависит компонент, не был загружен, когда React хочет отобразить компонент?<React.Suspense/>появился, чтобы помочь нам решить проблему. Прежде чем код будет загружен, он отобразит значение, переданное в резервном свойстве. Итак, наш исходный код:

return (
        <div>
            <MainComponet />
            <LazyComponent />
        </div>
    )

изменить на:

return (
        <div>
            <MainComponet />
            <React.Suspense fallback={<div>正在加载中</div>}>
                <LazyComponent />
            </React.Suspense>
        </div>
    )

В качестве запасного варианта его можно изменить на любой счетчик, и на этот раз мы не будем слишком много оптимизировать. React выдаст вам ошибку, если вы не используете React.suspense, поэтому не забудьте использовать React.lazy с React.Suspense. На данный момент по сетевому запросу мы видим, что динамически загружаемый lazyComponent упакован в бандл отдельно, однако при загрузке первого экрана бандл уже загружен на нашу страницу, что может быть не тем, что нам нужно. , мы хотим перезагружаться, когда нам это нужно. Затем мы берем на себя управление и загружаем файл, когда он нам нужен.

3. Загрузка через переменное управление

Первоначально все пять компонентов с отложенной загрузкой, которые я выбрал, были компонентами эластичного слоя, поэтому необходимо установить состояние для управления отображением и скрытием компонента, поэтому мы изменили код на:

return (
        <div>
            <MainComponet />
            {this.state.showLazyComponent && (
                <React.Suspense fallback={<div>正在加载中</div>}>
                    <LazyComponent />
                </React.Suspense>
            )}
        </div>
    )

В результате при загрузке первого экрана наш компонент ленивой загрузки не загружаетсяLazyComponentСоответствующий пакет пакета. Страница не будет загружать JS, пока не нажму на компонент, который необходимо отобразить. Это достигает цели нашего разделения кода и ленивую нагрузку. Поэтому, когда мы это делаем, имеет объем главного пакета пакета? Далее давайте посмотрим на файл пакета.

4. Файл пакета

Упакованные файлы перед оптимизацией:

image.png

Запакованные файлы после оптимизации:

image.png

app.jsФайл становится меньше и растет вместе с нимlazyComponent.js. Когда есть много компонентов ленивой загрузки, мы можем в определенной степени уменьшить размер файла загрузки первого экрана и улучшить скорость рендеринга первого экрана. В этом эксперименте в качестве примера используется только один компонент.Если количество ленивых загрузок велико, этого достаточно, чтобы значительно уменьшить размер app.js.

Резюме --> Проверка эффективности оптимизации

5. [Проверьте своевременность оптимизации] Используйте Puppeteer и Performance API для сравнения

Чтобы проверить эффективность сделанной ранее оптимизации, я провел серию сравнительных экспериментов. Содержание эксперимента состоит в том, чтобы использовать puppeteer для посещения страниц до и после оптимизации 1000 раз соответственно, а также использовать Performance API для подсчета среднего значения пяти элементов данных в этих 1000 посещениях. Результаты эксперимента показаны на рисунке ниже, где:

  • A - среднее время запроса запроса
  • B — среднее время, затрачиваемое на синтаксический анализ дерева dom.
  • C — среднее время от завершения запроса до загрузки DOM.
  • D — среднее время от начала запроса до конца события domContentLoadedEvent.
  • E — среднее время от начала запроса до загрузки

image.png


Линейный график не может точно отобразить данные, поэтому данные в прикрепленной таблице выглядят следующим образом (все среднее времязатратно):

категория Оптимизировано До оптимизации

А (запрос запроса)

7.01 7.04

B (среднее значение дерева синтаксического анализа)

30.28 32.59

C (запрос выполняется до загрузки DOM)

552.86 582.0

D (просит начать закончить DomContentLoadEvent)

569.13 589.0

E (от начала до конца загрузки)

1055.59 1126.94

Из данных видно, что время запроса до и после оптимизации не влияет, но общее время загрузки значительно сокращается и сразу выходит на отметку в 1000 мс.Видно, что скорость загрузки первого экрана все же значительно улучшилась. после оптимизации.

Примечание. В процессе запуска puppeteer 1000 раз будут возникать колебания сети, что приведет к большому объему запрашиваемых данных, поэтому среднее значение не может полностью отражать нормальное время запроса. Но в среднем 1000 раз достаточно, чтобы сравнить время запроса до и после оптимизации.

6. [Проверьте своевременность оптимизации] Используйте параметры производительности Chorme для сравнения

Поскольку параметры, предоставляемые Performance API, ограничены, я получил параметры для запроса одной страницы из сводки производительности браузера Chrome. Поскольку это единичные данные, мы не проводим подробного сравнения. Перечислено здесь только для того, чтобы показать, какие части времени рендеринга в браузере улучшились до и после оптимизации. До оптимизации: После оптимизации:

image.png image.png

  • Синий: время загрузки уменьшено.
  • Желтый: время выполнения сценария уменьшено.
  • Фиолетовый: время рендеринга уменьшилось.
  • Зеленый: время рисования плоское
  • Серый: Другое (Другое) время сокращено
  • Idle: сокращено время простоя браузера.

Кроме того, я нашел из сети, что после оптимизации, поскольку парсинг страницы происходит относительно быстрее, чем раньше, время запроса основного интерфейса соответственно меньше.

4. Резюме

По ряду данных видно, чтоReact.lazyа такжеReact.SuspenseЕго использование в определенной степени ускоряет отрисовку первого экрана, ускоряя загрузку наших страниц. Кроме того, когда мы хотим добавить новую функцию и ввести новую зависимость, мы часто оцениваем размер зависимости и то, какое влияние введение зависимости окажет на исходный пакет. Если эта функция редко используется, то мы можем использовать ее с удовольствиемReact.lazyа такжеReact.Suspenseчтобы загружать функцию по запросу, не жертвуя удобством для пользователя.

4. Используйте React.memo() для оптимизации производительности функциональных компонентов.

Еще один, добавленный eact16.6, посвящен оптимизации.функциональный компонент(Функциональный компонент) метод выполнения:React.memo.

1. Бесполезный рендеринг

Компонент — это базовая единица, из которой состоит представление React. Некоторые компоненты будут иметь собственное локальное состояние, которое будет повторно отображаться при изменении их значения из-за действий пользователя. В приложении React компонент может часто отображаться. Хотя небольшой процент этих рендеров необходим, большинство из них бесполезны и их присутствие может сильно снизить производительность нашего приложения.
Рассмотрим следующий пример:

import React from 'react';

class TestC extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }
    
    componentWillUpdate(nextProps, nextState) {
        console.log('componentWillUpdate')
    }
    
    componentDidUpdate(prevProps, prevState) {
        console.log('componentDidUpdate')
        
    }
    
    render() {
        return (
            <div >
            {this.state.count}
            <button onClick={()=>this.setState({count: 1})}>Click Me</button>
            </div>
        );
    }
}
export default TestC;

Компонент TestC имеет локальный счетчик состояний, начальное значение которого равно 0 (состояние = {count: 0}). Когда мы нажимаем кнопку Click Me, значение count устанавливается равным 1. В это время число на экране изменится с 0 на 1. Когда мы снова нажимаем кнопку, значение count по-прежнему равно 1. В это время компонент TestC не должен повторно отображаться, но так ли это?

Чтобы проверить, будет ли компонент повторно отображаться путем многократной установки одного и того же значения count, я добавил в компонент TestC две функции жизненного цикла: componentWillUpdate и componentDidUpdate. Метод componentWillUpdate вызывается перед повторной визуализацией компонента, а метод componentDidUpdate вызывается после успешной повторной визуализации компонента.

Запустите наш код в браузере и несколько раз нажмите кнопку Click Me, вы увидите следующий вывод:


Мы видим, что 'componentWillUpdate' и 'componentWillUpdate' выводятся на консоль каждый раз, когда мы нажимаем кнопку. Таким образом, даже если для счетчика задано то же значение, компонент TestC все равно будет перерендерен, это так называемый бесполезный рендеринг.

2. Функциональные компоненты

Выше мы обсуждали, как использоватьPureComponentа такжеshouldComponentUpdateметод оптимизации производительности компонентов класса. Хотя компоненты класса являются основной частью приложений React, функциональные компоненты также могут использоваться в качестве компонентов React.

function TestC(props) {
    return (
        <div>
            I am a functional component
        </div>
    )
}

Для функции компонентов они не являются чем-то вроде состояния для сохранения своего собственного состояния (хотя вы можете использовать useState в React Hooks в компонентах функций для использования состояния), поэтому мы не можем быть похожими на использование shouldComponentUpdate и других жизненно важных функций в классе компонент для управления функцией повторного рендеринга компонентов. Конечно, мы не можем использовать расширения React.PureComponent, потому что это совершенно не класс.

Чтобы исследовать решение, давайте сначала убедимся, что функциональные компоненты имеют ту же проблему бесполезного рендеринга, что и компоненты класса.

Во-первых, давайте преобразуем класс ES6 TestC в функциональный компонент:

import React from 'react';

const TestC = (props) => {
    console.log(`Rendering TestC :` props)
    return ( 
        <div>
            {props.count}
        </div>
    )
}
export default TestC;
// App.js
<TestC count={5} />


Точно так же мы можем открыть инструменты отладки Chrome, щелкнуть вкладку React и выбрать компонент TestC:


Мы видим, что значение параметра этого компонента равно 5, давайте изменим это значение на 45, тогда браузер выводит


Поскольку значение count изменилось, компонент также перерисовывается, и консоль выводит Object{count: 45}. Давайте повторно установим значение count равным 45, а затем посмотрим на вывод консоли:

Как видно из вывода, несмотря на то, что значение count остается прежним, равным 45, компонент все равно перерисовывается.

Поскольку функциональные компоненты также имеют проблему бесполезного рендеринга, как мы можем их оптимизировать?

3. Решение: используйте React.memo()

React.memo(...)— это новое свойство, представленное в React v16.6. его роль иReact.PureComponentТочно так же он используется для управления повторным рендерингом функциональных компонентов.React.memo(...)По сути, это функциональный компонент.React.PureComponent.

Как использовать React.memo(...)?

React.memo очень прост в использовании, если у вас есть следующий функциональный компонент:

const Funcomponent = ()=> {
    return (
        <div>
            Hiya!! I am a Funtional component
        </div>
    )
}

Мы просто передаем указанный выше Funcomponent в React.memo в качестве параметра:

const Funcomponent = ()=> {
    return (
        <div>
            Hiya!! I am a Funtional component
        </div>
    )
}
const MemodFuncComponent = React.memo(FunComponent)

React.memo вернеточищение(очищенные) компонентыMemoFuncComponent, компонент будет отображаться в разметке JSX. Когда реквизиты параметров и состояние состояния компонента изменяются, React проверяет, совпадают ли предыдущее состояние и параметры со следующим состоянием и параметрами. Если они совпадают, компонент не будет отображаться. Если они отличаются, компонент будет перерендерен.

Теперь давайте оптимизируем с помощью React.memo компонент TestC:

let TestC = (props) => {
    console.log('Rendering TestC :', props)
    return ( 
        <div>
        { props.count }
        </>
    )
}
TestC = React.memo(TestC);

Откройте браузер и перезагрузите наше приложение. Затем откройте отладчик Chrome, перейдите на вкладку React и выберите<Memo(TestC)>компоненты.

Затем отредактируйте значение реквизита, измените количество на 89, и мы увидим, что наше приложение перерисовывается:


Затем повторно установите счетчик на 89:


Здесь нет повторного рендеринга!

Вот тут-то и пригодится функция React.memo(...)!

это не работало до насReact.memo(...)В примере повторная настройка счетчика вызовет повторную визуализацию компонента. Однако после того, как мы используем React.memo, компонент не будет перерисовываться, исходя из того, что входящее значение остается неизменным.

Компоненты высшего порядка (HOC)

Функции высшего порядка, функции, которые могут быть переданы в качестве параметров, такие как отображение, сортировка и уменьшение. Компонент более высокого порядка обертывает компонент другого компонента.

  1. Реквизит Прокси
  2. Инверсия наследования

Immutable.js

Поскольку данные неизменяемы, можно избежать проблемы передачи по ссылке, но это также проблематично.

компоненты без сохранения состояния

Использование компонентов без сохранения состояния, которые получают реквизиты только от родительского компонента, может улучшить производительность рендеринга компонента.

const HelloWorld = (props) => <div>{props.name}</div>ReactDOM.render(<HelloWorld name="HelloWorld" />,App)

Получить значение реквизита в componentWillReceiveProps

Обратите внимание, что следует брать nextProps, а не this.props.

привязать функцию привязки

Используя функцию привязки привязки, по умолчанию есть параметр события, но этот параметр находится после данного параметра.

handleClockClick (id, e) {console.log(id,e)}<button onClick={this.handleClockClick.bind(this, 2)}>Clock</button>

В классах ES6 функция this по умолчанию не указывает на объект.

получить элемент

  • this.getDomNode был удален в более ранних версиях, теперь установите ref=xxx, а затем используйте this.refs.xxx для доступа к элементам DOM.
  • ref может быть назначено два типа, один является строкой, а другой является функцией.Строки могут использоваться только в компонентах класса, элементы DOM используют функции, а чистые функциональные компоненты не могут использовать ref. Старые версии элементов DOM могут использовать ссылки, но в React они объявлены устаревшими.

ref="test" // this.refs.test 访问ref={test => this.test = test} // this.test 访问

Композиция против наследования

React рекомендует использовать композицию вместо наследования.Композиция более интуитивно понятна в пользовательском интерфейсе, а код выглядит проще, что больше соответствует нашему познанию и характеристикам компонентной базы React.

Когда записывается только имя свойства, значением по умолчанию является true

<MyComponent isStock/>// isStock 默认为 true

createPortal

  • Метод подключения дочерних узлов к компонентам, отличным от родительского компонента, используется в методе рендеринга и не может быть подключен к родительскому компоненту, потому что родительский компонент в это время плохо визуализируется, и DOM не может быть получен.
  • Поведение ничем не отличается от других дочерних узлов, потому что дерево React DOM все еще находится в этом компоненте, включая такие вещи, как всплывающее окно событий.
import { createPortal } from 'react-dom'createPortal(this.props.children, document.getElementById('portal-root'))

граница ошибки

граница ошибки componentDidCatch, определяет родительский компонент для компонента, родительский компонент перехватывает ошибку и предоставляет резервный пользовательский интерфейс

  • Применение
componentDidCatch(error, info) {this.setState({ hasError: true });console.log(error, info)}
  • неуловимая ошибка
    обработка событий
    Асинхронный код (например, функции обратного вызова setTimeout или requestAnimationFrame)
    рендеринг на стороне сервера
    Ошибки, вызванные самой границей ошибки (а не ее дочерними компонентами)

Расширенные компоненты — это функции

  • Свойства исходного компонента не должны изменяться в компоненте более высокого порядка.
  • Оберните компонент функцией и верните новый компонент
  • Переключение между различными источниками данных для компонентов
  1. Компонент Showcase, обернутый функцией getData (Showcase, data) для получения разных данных
  • Не используйте компоненты более высокого порядка в рендере
    Потому что каждый раз, когда компонент монтируется, экземпляр компонента более высокого порядка будет повторно получен.
  • hoistNonReactStatic
    Скопируйте статический метод исходного компонента в обернутый компонент.

компонент контейнера

  • Обработка подписок на данные и управление состоянием
  • Компоненты высшего порядка — это параметризованные компоненты-контейнеры.

rander prop

Заголовок тот же, а заголовок отображается в другом компоненте с использованием компонента более высокого порядка.

Использование веб-компонентов в React

В настоящее время следует отметить, что для веб-компонентов вы должны использовать class вместо className.

для этикетки

for — это зарезервированное слово в JS, поэтому используйте htmlFor вместо for

свойство стиля

Все суффиксы браузера, кроме ms, должны начинаться с заглавной буквы. Вот почему WebkitTransition имеет заглавную букву W.

const divStyle = {WebkitTransition: 'all', // note the capital 'W' heremsTransition: 'all' // 'ms' is the only lowercase vendor prefix};

Используйте React16 ниже IE11

React16 опирается на типы коллекций Map и Set.В браузерах, которые не обеспечивают встроенную поддержку, вам необходимо использовать полифилл, такой как core-js и babel-polyfill

Используйте поддержку core-js

import 'core-js/es6/map';import 'core-js/es6/set';import React from 'react';import ReactDOM from 'react-dom';ReactDOM.render(<h1>Hello, world!</h1>,document.getElementById('root'));

componentDidMount запрашивает данные сервера

Когда componentDidMount запрашивает данные сервера и использует setState, следует отметить, что когда компонент размонтирован, componentWillUnmount должен удалить запрос.

Передайте реквизиты компонентов, используя новые функции es6

const {data, type} = this.state;
// 一般方法
<Demo data={data} type={type}/>
// es6方法
<Demo {...{data, type}}/>

3. Используйте остальные параметры es6 (в виде ... имени переменной) для передачи переменного количества реквизитов.

// 定义子组件
const Demo = ({ prop1, prop2, ...restProps }) => (
<div>{ restProps.text}</div>
)
// 父组件使用Demo
<Demo prop1={xxx} prop2={xxx} text={xxx}/>

4. Другое использование setState

// 一般改变state值的一种方式
const { data } = this.state;
this.setState({ data: {...data, key: 1 } });
// 另外一种可以通过callback的方式改变state的值
this.setState(({ data }) => ({ data: {...data, key: 1 } }));
// 还可以
this.setState((state, props) => {
return { counter: state.counter + props.step };
});

5. Реагировать на оптимизацию производительности

// React 性能优化有很多种方式,
// 那常见的一种就是在生命周期函数shouldComponentUpdate里面判断
// 某些值或属性来控制组件是否重新再次渲染。
// 判断一般的字符串,数字或者基础的对象,数组都还是比较好处理
// 那嵌套的对象或者数组就比较麻烦了,对于这种
// 推荐使用lodash(或者其他的类似库)的isEqual对嵌套数组或对象进行判断
shouldComponentUpdate(nextProps, nextState) {
if (_.isEqual(nextState.columns, this.state.columns)) return false;
return true;
}

React Advanced Improvement - Советы (28 видео) ссылка

Познакомьте с некоторыми дополнительными знаниями React, некоторыми практическими навыками разработки, некоторыми библиотеками инструментов и т. д.

Адрес обновления видео:www.qiuzhi99.com/

Расширенное улучшение React — советы

Уловка #1, как развернуть приложение React с облачным сервисом netlify 65"07:14"

Уловка #2. Развертывание реагирующих приложений на GitHub Pages 18"05:34"

Трюк с реакцией #3: учебник по реактивному маршрутизатору, часть 1 51«10:29»

Трюк с реакцией #4. Учебное пособие по реактивному маршрутизатору, часть 2 11"07:39"

React Advancement #5 Лучший способ написания компонентов без сохранения состояния 44«Про» «04:52»

Расширенные улучшения React #6 Фрагмент 14«Про» «02:36»

Расширенные улучшения React #7, контекст 9"03:58"

React Advancement #8 Компоненты высшего порядка 14«Про» «02:51»

Расширенное улучшение React #9 Мощный крутой и интересный инструмент веб-IDE (щелкните мышью, чтобы сгенерировать код, сократить время разработки в N раз) 12«Про» «08:20»

React Advancement #10 Рефакторинг кода с использованием компонентов высшего порядка 11"05:58"

Реагируйте шаг вверх # 11 мои любимые библиотеки React - мощные подключаемые компоненты (упрощенный код) 1«Про» «04:30»

React Advancement #12 Правильный способ возврата нескольких компонентов 5«Про» «03:07»

Расширенное улучшение React # 13 netlifyctl развертывание интерфейсных приложений одним щелчком мыши 2"06:49"

React Advancement #14 defaultProps и проверка типов PropTypes часть 1 4"06:37"

React Advancement #15 Проверка типов PropTypes часть 2«Про» «09:57»

React Advancement #16 Замените HOC (компоненты более высокого порядка) на Render Props 5"Про" ""

Улучшения React Advanced #17 Границы ошибок и функции жизненного цикла componentDidCatch 9«Про» «11:45»

Обновление React #18 до версии 16.3"02:37"

React Advanced Improvement #19 Узнайте, как пишется bind (this) 9"03:50"

Расширенные улучшения React #20 React 16.3 New Context API 1"06:50"

Расширенные улучшения React #21 React 16.3 New Context API — практика 3«Про» «09:19»

React Advancement #22 Миграция с Redux на контекстный API React 16.3 на практике 1«Про» «11:37»

React Advanced #23 Объекты, массивы, изменяемые данные 9«Про» «06:10»

Расширенное улучшение React #24 Объяснение API React.Children и props.children 4«Про» «06:06»

React Advancement #25 Как использовать стилизованные компоненты 5«Про» «04:56»

Расширенное улучшение React #26 Как использовать стилизованные компоненты (практика)«Про» «07:29»

React Advancement #27 Вы должны использовать редукционную форму (вступление) 12«Про» «06:40»

React advanced # 28 Вы должны использовать REDUX-FORM (Практика) 7«Про» «10:34»

учебные материалы

материал

doc.react-china.org/Для переведенных официальных документов вы должны прочитать документы несколько раз, чтобы изучить технологию.

Маленькая книга ReactНастоятельно рекомендуется, от мелкого к глубокому, шаг за шагом

reactpatterns.com/Поскольку сам API реакции относительно прост, он близок к нативному. Создание серии шаблонов путем изменения компонентов

GitHub.com/com PU Ives/ Из…Онлайн-редактор React, с которым легко поделиться своим проектом React

image.png

devhints.io/react

image.png

js.coachСайт для поиска пакетов js

image.png

видео

Базовая бесплатная, расширенная платаegghead.io