React — это библиотека JavaScript, запущенная Facebook, и ее слоган — «Библиотека JavaScript для создания пользовательских интерфейсов", поэтому он имеет дело только с пользовательским интерфейсом, вы можете думать об этом как о слое V (представление) в MVC. Сейчас существует множество фреймворков и библиотек в области внешнего интерфейса, так что же делает React таким популярным? Просто сказал три его подрывные черты:Компоненты, JSX, виртуальный DOM.
Эта статья знакомит, в свою очередь,Компоненты, JSX, Virtual DOM, архитектура Flux, Redux, react-redux и оптимизация производительности.
1. Компоненты
Все в React основано на компонентах. Композиция веб-мира основана на сочетании различных тегов HTML, которые по своей сути являются выражением семантических компонентов, а некоторый контент представляет собой сочетание этих тегов, например, набор слайдов, интерфейс профиля, набор боковых панелей. Навигацию и т. д. можно назвать пользовательскими компонентами. Самая важная особенность React — процесс проектирования, основанный на компонентах. С React ваша единственная забота — это создание компонентов. Компоненты имеют хорошую инкапсуляцию, а компоненты упрощают повторное использование, тестирование и разделение кода. Каждый компонент имеет свое собственное состояние, и при изменении состояния весь компонент перерисовывается. Функция компонента — это не только патент React, но и тенденция развития будущего Интернета. React следует веяниям времени, поэтому вполне естественно, что он так популярен.
组件是React的基石,所有的React应用程序都是基于组件的。
свойство реквизита
Теперь создайте новый компонент с именем Profile.jsx; Пример компонента выглядит следующим образом:
// Profile.jsx
import React from 'react' ;
export default Class Profile extends React.Component {
// render 是这个组件渲染的Vitrual DOM结构
render() {
return (
<div className-"profile-component">
</*this.props就是传入的属性*/>
<h1>my name is {this.props.name}</h1>
<h2>my age is {this.props.age}</h2>
</div>
)
}
}
Таким образом реализуется компонент React, на который можно ссылаться как на теги HTML в других компонентах. После того, как у вас есть компонент, вы можете использовать другую библиотеку, предоставленную React, ReactDOM, для монтирования компонента на узле DOM.
// app.jsx
import { render } from 'react-dom';
import Profile from './profile';
render(<Profile name="lewis" age=26 />, document.getElementById('app'));
// 或者可以使用...属性拓展
const props = {
name: 'lewis',
age: 26
};
render(<Profile {...props} />, document.getElementById('app'));
состояние
state — это свойство внутри компонента. Сам компонент представляет собой конечный автомат, который может напрямую определять свое значение через this.state в конструкторе, а затем отображать различные пользовательские интерфейсы на основе этого значения. Когда значение состояния изменяется, вы можете использовать метод this.setState, чтобы компонент снова вызывал метод рендеринга для рендеринга нового пользовательского интерфейса. Теперь преобразуйте простой компонент, добавьте к нему состояние, кнопку «Нравится» и прибавьте 1 к количеству лайков при каждом нажатии.
//Profile.jsx
export default class Profile extends React.Component {
constructor (props) {
super (props);
this.state = {
liked: 0
};
this.likedCallback = this.likedCallback.bind(this);
}
likedCallback() {
let liked = this.state.liked;
liked++;
this.setState({
liked
});
}
render() {
return (
<div>
<h1>我的名字叫{this.props.name}</h1>
<h2>我今年{this.props.age}</h2>
<button onClick={this.likedCallback}>点赞</button>
<h2>总点赞数:{this.state.liked}</h2>
</div>
)
}
}
Как описано выше, добавьте определение this.state в конструктор, вызовите функцию обратного вызова каждый раз, когда нажимается кнопка, добавьте 1 к текущему понравившемуся значению, а затем обновите this.setState, чтобы завершить повторную визуализацию пользовательского интерфейса. Поскольку в методе объявления компонента типа класса ES6 некоторые пользовательские функции обратного вызова не будут привязаны к экземпляру, поэтому их необходимо вручную привязать в конструкторе.
this.likedCallback = this.likedCallback.bind(this);
Компоненты React используют метод рендеринга для генерации экземпляра компонента из значений реквизита и состояния.
Жизненный цикл
1. Компонент загружается впервые- getDefaultPropsОн будет вызываться только один раз перед загрузкой, а данные, назначенные в компоненте, будут установлены в this.props.
- getInitialStateОна будет вызываться только один раз перед загрузкой, а возвращаемое значение этой функции будет установлено в this.state.Следует отметить, что при написании ES6 ее нужно только записать в конструкторе следующим образом:
class MyComponent extends React.Component {
constructor (props){
super (props) ;
//在这里声明state
this.state = {count: 0} ;
}
}
- componentWillMountВызывается перед рендерингом, может выполнить некоторую подготовительную работу перед рендерингом.
- renderЭтот метод является компонентомнеобходимый метод. Когда этот метод вызывается, он должен возвращать объект ReactElement, рендеринг — это чистая функция, и его смысл в том, что при задании одних и тех же условий его возвращаемый результат каждый раз должен быть точно таким же. Не должно быть никакого кода, который изменяет состояние компонента или взаимодействует с браузером.
- componentDidMountОн будет вызываться только один раз после завершения загрузки и после рендеринга, чтобы получить отсюда DOM-структуру компонента. Если вы хотите выполнить какие-то дополнительные операции (например, AJAX-запросы и т. д.) после загрузки компонента, вы можете добавить соответствующий код в этот метод.
2. Обновление реквизита компонента
Когда компонент получает новые реквизиты, по очереди запускаются следующие методы.
- componentWillReceiveProps(nextProps)Запускается, когда компонент получает новые реквизиты, параметр nextProps — это входящие новые реквизиты, вы можете использовать его для сравнения с this.props, чтобы решить, следует ли использовать this.setState для достижения повторного обесцвечивания пользовательского интерфейса;
- shouldComponentUpdateВызванный перед повторной визуализацией, он может возвращать логическое значение, чтобы определить, следует ли обновлять компонент. Если он возвращает значение fse, предыдущий процесс не будет запущен. Возвращаемое значение по умолчанию для этого метода — true.
- componentWillUpdateВызывается перед рендерингом, может выполнить некоторую подготовку перед рендерингом, аналогично componentWillMount.
- renderТот же метод, что и при первой загрузке компонента.
- componentDidUpdateВызывается сразу после повторного рендеринга, аналогично componentDidMount.
3. Удаление компонента
- componentWillUnmountМетод, вызываемый перед размонтированием и уничтожением компонента, может выполнить некоторую очистку здесь.
Комбинированные компоненты
Приложения React построены на различных компонентах, поэтому, естественно, компонент может также содержать несколько других компонентов.
Функциональные компоненты без состояния
Функциональные компоненты без состояния не имеют внутреннего состояния и не нуждаются в функциях жизненного цикла компонента, поэтому этот тип компонента может быть записан в виде чистой функции, называемой функциональным компонентом без состояния (stateless function component), которая генерируется только на основе входных данных. , никаких других побочных эффектов, и все просто и понятно.
// 用一个纯函数表示组件
function Hobby (props) {
return <li>{props .hobby)</li>;
}
Этот способ написания очень прост, напрямую экспортирует функцию, он имеет только один параметр props, который является входящим свойством. В реальных проектах большинство компонентов являются функциональными компонентами без состояния, поэтому React рекомендует именно этот способ.
принципы государственного проектирования
Какие компоненты должны иметь состояние и должны следовать рекомендациям по минимизации состояния? Чтобы достичь такой структуры, состояние должно быть разделено на некоторые конкретные компоненты, насколько это возможно, чтобы уменьшить сложность компонентов. Наиболее распространенный подход заключается в создании как можно большего количества компонентов без сохранения состояния, единственной задачей которых является рендеринг данных. А во внешнем слое этих компонентов должен быть компонент родительского уровня, содержащий состояние. Этот компонент используется для обработки различных событий, передачи логики и изменения состояния.Соответствующие подкомпоненты заботятся только о входящих свойствах.
Какие данные должно содержать состояние?Состояние должно содержать такие данные, чтобы функция обратного вызова события компонента могла запускать обновления пользовательского интерфейса.. В реальных проектах это должны быть облегченные данные JSON, а производительность данных должна быть сведена к минимуму, а больше данных можно получить с помощью различных вычислений в методе рендеринга.
Манипуляции с DOM
В большинстве случаев вам не нужно обновлять пользовательский интерфейс, манипулируя DOM, вы должны использовать setState для повторного рендеринга пользовательского интерфейса, но в некоторых случаях вам действительно нужно получить доступ к некоторым структурам DOM (таким как значения формы), тогда вы Для этого можно использовать refs.Чтобы получить DOM-узел, необходимо установить атрибут ref на применяемом узле, а затем получить соответствующую DOM-структуру через this.refs.name.
// Profile.jsx
render() {
return (
<div>
<input type="text" ref="hobby" />>
<button onClick={this.addHobbyCallback}>添加爱好</button>
</div>
)
}
addHobbyCallback() {
//用this.refs.name来取得DOM节点
let hobbyInput = this.refs.hobby;
let val = hobbyInput.value;
if (val) {
let hobbies = this.state.hobbies;
//添加值到数组
hobbies = [...hobbies, val];
//更新state,刷新UI
this.setState({
hobbies
}, ()=>{
hobbyInput.value = '';
});
}
}
Компоненты — это ядро React, а проект на основе React состоит из различных компонентов.
2. JSX
Как видно из приведенного выше примера, существует способ прямого вложения HTML в JS в методе рендеринга, который называется JSX. Это XML-подобный способ написания, который может определять древовидную структуру так же просто, как HTML. Этот синтаксис сочетает в себе преимущества JavaScript и HTML, либо используя обычный HTML, либо встраивая синтаксис JavaScript внутрь. Этот дружественный формат облегчает разработчикам чтение и разработку. А для компонентов тоже очень разумно напрямую использовать HTML-подобные форматы. Однако важно это отметить. JSX и HTML — это совсем не одно и то же, JSX просто действует как компилятор, компилирующий HTML-подобные структуры в JavaScript. Конечно, этот формат нельзя использовать непосредственно в браузере, и для выполнения этой работы необходимо добавить компилятор JSX.
источник
Следующий абзац является ссылкой на официальную документацию, которая может объяснить первоначальное намерение JSX.
We strongly believe that components are the right way to separate concerns rather than "templates" and "display logic." We things that markup and the code that generates it are intimately tied together. Additionally, display logic is often very complex and using template languages to express it becomes cumbersome.
На протяжении многих лет в традиционной разработке разделение шаблонов и функций считалось прекрасным примером наилучшего мероприятия.Просматривая различные документы фреймворка, всегда есть папка с шаблонами, куда помещаются соответствующие файлы шаблонов, а затем обрабатываются механизм шаблонов Строки для генерации символов, которые объединяют данные с шаблонами. React считает, что мир основан на компонентах, а компоненты естественным образом связаны с шаблонами, и разделять логику и шаблоны — громоздкая идея. Итак, React создал формат синтаксиса под названием JSX, чтобы связать их.
грамматика
- JSX не требуется
Компилятор JSX преобразует записи, подобные HTML, в собственные методы JavaScript и преобразует входящие свойства в соответствующие объекты. Это похоже на синтаксический сахар, который преобразует тип метки в метод, предоставляемый React для создания ReactElement.
const MyComponent ;
//input JSX, 在JS中直接写类似的内容。前所未有的感觉。其实它返回的是一个ReactElement
let app = <h1 title="my title">this is my title</h1>;
//JSX转换后的结果
let app = React.createElement('hl', {title: 'my title'}, 'this is my tit
le');
- HTML-теги и компоненты React
React может напрямую отображать теги типа HTML, а также компоненты React.
Первая буква тегов типа HTML представлена строчными буквами.
import React from 'react';
//当一个标签里面为空的时候,可以直接使用自闭和标签
注意class是一个JavaScript保留字,所以如果要写class应该替换成classname
let divElement = <div className="foo" />;
//等同于
let divElement = React.createElement('div", {className: 'foo'});
Первая буква метки компонента React заглавная.
import React from 'react';
class Headline extends React.component {
render(){
//直接returnJSX语法
return (
<hl>He1lo React</h1>
)
}
}
let headine = <Headline />;
//等同于
let headline = React.createElement(Headline);
Синтаксис JSX использует регистр первых букв, чтобы различать обычный HTML-тег и компонент React.
Примечание. Поскольку JSX сам по себе является синтаксисом JavaScript, некоторые зарезервированные слова в JavaScript должны быть записаны другими способами, например, class в первом примере должен быть записан как className.
- JavaScript-выражения
При передаче свойств компоненту в большинстве случаев необходимо передать объект JavaScript, поэтому основное правило заключается в том, что при встрече с выражением {} код внутри будет рассматриваться как код JavaScript.
Выражение свойства выглядит следующим образом.
const MyComponent;
let isLoggedIn = true;
let app = <MyComponent name={isLoggedIn ? 'viking' : 'please login'}/>`
Выражения подкомпонентов следующие.
const MyComponent, LoginForm, Nav;
let isLoggedIn = true;
let app = <MyComponent>{isLoggedIn ? <Nav/> : <LoginForm/> }</MyComponent>
Основное правило можно получить из приведенных выше двух примеров. В синтаксисе JSX при обнаружении тега он интерпретируется как компонент или тег HTML, а при обнаружении пакета {} он выполняется как код JavaScript. Свойства логического типа следующие.
Когда значение свойства опущено, JSX автоматически считает его значение истинным.
let myButton = <input type="button" disabled />;
//等同于
let myButton = <input type-"button" disabled={true}/>;
- Примечания
Чтобы использовать комментарии в JSX, следуйте методу JavaScript, следует отметить, что позиция дочернего компонента должна быть заключена в {}.
let component = (
<div>
{/* 这里是一个注释! */}
<Headline />
</div>
);
- Распространение свойств JSX
Если компонент имеет много свойств, конечно, это можно сделать следующим образом.
const Profile;
let name = 'viking', age = 10, gender = 'Male';
let component = <Profile name={name} age={age) gender={gender} />;
Однако, когда таких свойств слишком много, написание и форматирование выглядят сложными, поэтому в JSX реализовано очень удобное распределение свойств-функций.
const Profile;
let props = {
name: 'viking',
age: 10,
gender: 'Male'
};
//用这种方式可以很方便地完成上一个例子里面的操作
let component = <Profile {...props) />;
Вы можете использовать этот метод несколько раз и в сочетании с другими свойствами. Следует отметить, что порядок важен, более поздние атрибуты переопределяют более ранние атрибуты.
let component = <Profile {...props} name='viking2' />;
console.log (component.props.name) ;
//viking2
В чем волшебство "..."? Оператор "..." (оператор распространения) широко использовался на массивах ES6, а оператор распространения объектов также будет реализован в ES7, здесь JSX Он напрямую реализует будущий JavaScript, что приносит больше удобства.
- Скомпилировать JSX
JSX нельзя использовать непосредственно в браузере. Для его компиляции в метод React.createElement необходим инструмент компиляции. Теперь компилятор, предоставляемый Babel, обычно используется для компиляции кода JSX.
резюме
JSX выглядит как HTML, и каждый фронтенд-разработчик может быстро к нему привыкнуть. Однако имейте в виду, что на самом деле это не HTML и не имеет ничего общего с DOM. Это как синтаксический сахар для React.createElement. Это быстрый и эффективный способ написать эту функцию, которая возвращает ReactElement, структуру данных JavaScript.
3. Virtual DOM
При разработке React разработчикам не нужно манипулировать реальными узлами DOM. Каждый компонент React визуализируется с помощью Virtual DOM, который представляет собой абстрактное описание узлов HTML DOM. Вы можете думать об этом как о своего рода структуре. JavaScript, он не требует поддержки DOM API браузера, поэтому его также можно использовать в Node.js. Большая разница между ним и DOM заключается в том, что он использует более эффективный метод рендеринга.DOM-структура компонента сопоставляется с Virtual DOM.Когда компонент необходимо повторно визуализировать, React реализует алгоритм Diff в виртуальном DOM. Измените узел, а затем обновите изменения в нем. Для узла DOM, который действительно необходимо изменить, это позволяет избежать огромных затрат на рендеринг DOM в целом.
DOM
В современных веб-программах, в связи с появлением проектов типа SPA, древовидная структура DOM становится все более сложной, и ее изменения становятся все более частыми, может быть много операций DOM, таких как добавление, удаление или изменение некоторых узлов, необходимо обработать множество прослушивателей событий, обратных вызовов событий и уничтожения событий.Из-за изменений в древовидной структуре DOM будет вызвано большое количество перекомпоновок, что повлияет на производительность.
виртуальный элемент
Первое, что нужно сказать, это то, что Virtual DOM существует независимо от React, но React использует эту технологию для повышения эффективности при рендеринге. Как упоминалось ранее, DOM громоздкий и громоздкий, и он содержит множество API-методов. Структура DOM — это не что иное, как набор свойств и методов, так может ли она быть выражена в исходном виде JavaScript? Могут ли легковесные данные полностью заменить сложную структуру DOM для выражения того же содержимого? Ответ — да.
/*一个DOM结构,可以用JavaScript这么来表示
结构如下
<div id="container">
<h1>Hello world</h1>
</div>
*/
var element = {
tagName: 'div',
attr:{
props: {
id: 'container',
},
styles: {
color: 'red',
},
},
children: {
tagName: 'h1',
children: 'Hello world',
}
}
//用构造函数来模拟一下
function Element(tagName, props, children) {
this.tagName = tagName;
this.props = props;
this.children = children;
};
var headline = new Element('hi', null, 'Hello world');
var div = new Element('div', {
props: {
id: 'container',
},
styles: {
color: 'red',
},
}, headline);
Таким образом, объект используется для выражения структуры, похожей на узел DOM, который выглядит знакомо, верно?
Как видно из приведенного выше примера, JSX — это удобный способ создания ReactElement, а что такое ReactElement?
ReactElement — это облегченное, неизменяемое виртуальное представление элементов DOM без сохранения состояния. На самом деле это просто объект JavaScript для представления элемента DOM. Созданный нами объект Element и ReactElement выглядят совершенно одинаково.
Чтобы вставить ReactElement в настоящий DOM, вы можете вызвать метод рендеринга ReacDOM.
import { render } from react-dom';
import App from './app';
render(<App />,document.getElementById('root');
Метод рендеринга можно примерно записать так: создайте элемент DOM, используйте список атрибутов для перебора атрибутов нового элемента DOM и напишите псевдокод, используя объект Element.
function render(elemet, root) {
var realDOM = document.createElement(elemet.tagName);
//循环设置属性和样式,代码简化了解即可
var props = elemet.attr.props;
var styles = elemet.attr.styles;
for (var i in props) {
realDOM.setAttribute(i, props[i]);
}
for (var j in styles) {
realDOM.styles[j] = styles[j];
}
//循环子节点,做同样的事情
elemet.children.forEach(child => {
if (child instanceof Element) {
//如果是Element对象,递归该方法
render(child, realDOM);
} else {
//如果是Element对象,递归该方法
realDOM.appendChild(document.createTextNode(child));
}
});
// 最后插入到真实的DOM中
root.appendChild(realDOM);
return realDOM;
}
Обратите внимание, что приведенный выше код является псевдокодом, просто чтобы вы знали общий процесс рендеринга, и он не работает должным образом.
Представленный здесь, я не чувствую ничего необычного, виртуальный DOM — это просто описание JavaScript-объекта структуры DOM. Так где же он эффективнее и быстрее, чем DOM? Давайте представим его ниже.
Сравните различия
После понимания структуры виртуального DOM, когда происходит какое-либо обновление, эти изменения будут происходить в виртуальном DOM.Все эти модификации являются операциями над объектами JavaScript, и скорость очень высока. Когда серия обновлений завершена, создается новое дерево Virtual DOM. Для того чтобы сравнить сходства и различия двух деревьев, вводится алгоритм Diff, который может вычислить разницу между старым и новым деревьями. До сих пор не было выполнено никаких манипуляций с DOM, только вычисления и манипуляции с JavaScript. В конце концов, эта разница будет применена к реальному элементу DOM, таким образом, манипуляции с DOM сведены к минимуму, а эффективность максимальна.
Так как алгоритм здесь довольно сложный, мы не будем его подробно объяснять, а обобщим весь процесс в виде псевдокода.
//1.构建Virtual DOM 树结构
var tree = new Element('div', {props: {id: 'test'}}, Hello there');
//2.将Virtual DOM 树插入到真正的DOM中
var root = render (tree, document.getElementById('container')) ;
//3. 变化后的新 Virtual DOM树
var newTree = new Element('div', {props: {id: 'test2'}},'Hello React');
//4.通过Diff算法计算出两棵树的不同
var patches = diff(tree, newTree) ;
//5.在DOM元素中使用变更,这里引入了patch方法,用来将计算出来的不同作用到DOM上
patch(root, patches) ;
Через эти 5 шагов завершается весь процесс Virtual DOM.
4. Потоковая архитектура
FLux — это набор моделей архитектуры интерфейсных приложений, официально предложенных Facebook.Основной концепцией является односторонний поток данных. Это больше похоже на модель разработки программного обеспечения, чем на конкретный фреймворк, поэтому существует множество реализаций, основанных на Flux. На самом деле, использование архитектуры FLux для разработки программ не требует введения большого количества кода, ключом является его внутреннее мышление.
Однонаправленный поток данных
Однонаправленный поток данных лежит в основе Flux. Читатели могли ознакомиться с программной архитектурой MVC, а его поток данных является двунаправленным. Контроллер является средством взаимодействия между моделью и представлением. Он обрабатывает взаимодействие представления, уведомляет модель об обновлении и уведомляет представление об обновлении после успешной операции. Этот двусторонний режим становится все более и более в соответствии между моделью и представлением.Когда он сложный, он столкнется со многими трудностями, и его трудно поддерживать и отлаживать. Ввиду этого недостатка MVC, как работает однонаправленный поток данных Flux?
- Просмотр: просмотр слоя
- Действие (action): сообщение, отправленное уровнем представления (например, mouseClick)
- Диспетчер: используется для получения действий и выполнения функций обратного вызова.
- Store (уровень данных): используется для хранения состояния приложения, когда происходит изменение, напоминание представлениям об обновлении страницы.
dispatcher
Центр диспетчеризации событий, центральный узел модели Flux, управляет всеми потоками данных в приложении Flux. По сути, это регистрация обратного вызова для Магазина. Каждое хранилище регистрирует себя и предоставляет функцию обратного вызова. Когда диспетчер отвечает на действие, он отправляет полезные данные, предоставленные действием, во все хранилища в приложении через зарегистрированную функцию обратного вызова. синглтон уровня приложения;
store
Отвечает за инкапсуляцию взаимодействия между бизнес-логикой приложения и данными; Магазин содержит все данные приложения; Магазин — единственное место в приложении, где меняются данные; в Магазине нет интерфейса назначения — все изменения данных отправляется в хранилище диспетчером, а новые данные передаются обратно в представление с событием изменения, инициируемым хранилищем. Store выставляет во внешний мир только геттеры и не может предоставлять сеттеры.
view
Контроллер-представление можно понимать как контроллер в модели MVC, которым обычно управляет контейнер верхнего уровня приложения, отвечающий за получение данных из хранилища и передачу данных дочерним компонентам. Простые приложения обычно имеют только одно представление контроллера, а сложные приложения могут иметь несколько. Контроллер-представление — единственное место в приложении, которое может манипулировать состоянием (setState()).Вид (компонент пользовательского интерфейса) несет единую ответственность и позволяет вызывать действия для запуска событий, а данные передаются из верхнего контейнера через характеристики.
разное
Создатели действий, как вспомогательные функции диспетчера, обычно можно рассматривать как четвертую часть во Flux. ActionCreators относительно независимы, и в качестве синтаксической вспомогательной функции диспетчерам удобнее передавать данные в виде действий.
Грубый процесс
- Доступ пользователя к просмотру
- Представление выдает действие пользователя
- Диспетчер получает действие и просит магазин обновить его соответствующим образом.
- После обновления магазина создайте событие «change»
- После того, как View получит событие «change», обновите страницу
5. Redux
Redux — это контейнер состояния для JavaScript, обеспечивающий предсказуемое управление состоянием. Redux может работать в разных средах, будь то на стороне клиента, на стороне сервера или в собственных приложениях, которые могут запускать Redux. Обратите внимание, что между React и Redux нет особой связи, независимо от того, какой фреймворк вы используете, Redux можно применять к этим фреймворкам в качестве менеджера состояний.
три закона
1. Единственный источник правдыСостояние всего приложения хранится в объекте JavaScript, и Redux использует объект, называемый хранилищем, для хранения всего состояния.
2. состояние только для чтенияВы не можете изменять данные непосредственно в состоянии, единственный способ изменить состояние — запустить действие. Действие — это просто носитель информации, обычный объект JavaScript. Это гарантирует, что никакие другие операции не смогут изменить данные состояния, и вся модификация обрабатывается централизованно. и строгий Выполнять по порядку.
3. Используйте чистые функции для внесения измененийЧтобы описать, как действия изменяют состояние, необходимо написать редукторы, чтобы указать правила модификации. Редьюсер — это чистая функция, которая принимает предыдущее состояние и действие для обработки и возвращает новое состояние. Редьюсеры можно разделить на несколько редюсеров в зависимости от размера приложения, каждый из которых манипулирует разными частями состояния. Преимущество чистой функции в том, что она не имеет побочных эффектов, она зависит только от входных данных функции, а выходные данные должны оставаться неизменными при определении входных данных.
сочинение
1. action
Действие является носителем информации, которая содержит название действия и передаваемую информацию, которую затем можно передать в хранилище. Метод доставки заключается в использовании метода отправки магазина, а действие является единственным источником информации для магазина.
Как и во Flux, действие — это обычный объект JavaScript, действие должно иметь значение атрибута, похожее на идентификационную карточку этого действия, чтобы представить функцию, выполненную этим действием. тип должен быть определен как константа, поскольку он уникален и не может быть изменен. При увеличении сложности приложения все типы действий могут быть объединены в отдельный модуль.
action creatorПо сути, это функция, которая используется для создания различных экшенов, фактически это модификация функции, а возвращаемый объект так и остается объектом.
function createPost (data) {
return {
type: CREATE POST,
data: data
}
}
function deletePost (id) {
return {
type: DELETE POST,
id: id
}
}
function userLogin (data)
return {
type: USER LOGIN,
data: data
}
}
Возможно, здесь читатель запутается, зачем использовать функцию для обертывания процесса создания действия, это кажется совершенно ненужным. В синхронном приложении вроде бы ничего особенного, а вот в асинхронном просматривается роль создателя действия.
2. reducer
action определяет действие, которое должно быть выполнено, но не указывает, как изменяется состояние. Работа редюсера состоит в том, чтобы определить, как должно реагировать состояние всей программы.
В Redux все данные для всей программы хранятся в одном объекте. Это важная особенность Redux, которая отличается от Flux. Flux может иметь несколько хранилищ для обработки разных типов данных, в то время как все состояние приложения Redux находится в одном объекте. Можно написать только один редьюсер для обработки всех действий, но когда данные и действия становятся все более и более сложными, этот единственный редьюсер будет раздуваться, поэтому лучший способ — разделить сложный редюсер, а затем объединить.
3. store
До понимания Redux действие и редьюсер звучали довольно туманно, но на самом деле в них не было ничего сложного для понимания: действие — это просто специальный объект, описывающий конкретное поведение, а редюсер — это функция, которая принимает данные и действия и возвращает уникальное значение, обновит соответствующее значение состояния в соответствии с этими различными действиями.
Магазин является связующим звеном между ними и может выполнять следующие задачи.
- Сохраните состояние всей программы.
- Доступ к значению состояния можно получить с помощью метода getstate().
- Действие может быть выполнено через метод dispatch().
- Вы также можете зарегистрировать обратные вызовы через подписку (слушатель), чтобы отслеживать изменения состояния.
поток данных
Redux — это строгий односторонний поток данных, аналогичный Flux, который может сделать логику программы более четкой и полностью контролируемыми данными. Изменения данных в приложении следуют тому же циклу, который является слоганом Redux.Контейнер предсказуемого состояния JavaScript.
По приведенному выше примеру можно сделать вывод, что поток данных Redux делится на следующие этапы:
- Вызовите store.dispatch(action) для выполнения действия.
- Хранилище вызывает функцию входящего редуктора, источником хранилища является редьюсер, константное хранилище. = создать хранилище (корневой редуктор). Текущее состояние и действие будут переданы функции редуктора. в числе.
- Редьюсер обрабатывает действие и возвращает новое состояние. В чистой функции редуктора новое состояние может быть сгенерировано и возвращено в соответствии с входящим действием.
- В хранилище хранится полное состояние, возвращаемое редьюсером. Вы можете получить текущее состояние в соответствии с store.getState() или прослушивать изменения в состоянии с помощью store.subscribe(listener).
middleware
Middlear, как следует из названия, является промежуточным программным обеспечением. Если вы разрабатывали веб-сервер на базе Express/Koa, скорее всего, вы сталкивались с этой концепцией. В серверных фреймворках, таких как Express/Koa, промежуточное ПО играет роль в выполнении определенных действий при обработке в системе запрос/ответ, они могут получить доступ к запросу/ответу и следующему методу, который запускает следующее промежуточное ПО для продолжения обработки.
Дизайн mdeware в Redux также схож.Они запускаются при отправке действия и предоставляют возможность расширения перед вызовом окончательного редьюсера.Промежуточное ПО может одновременно получать доступ к информации о действии и к методам getstate/dispatch хранилища. ПО промежуточного слоя может создавать новые действия и отправлять (преобразование действий, асинхронная обработка действий и т. д.) на основе исходного действия, а также может запускать некоторые дополнительные действия (например, ведение журнала). Наконец, он также может инициировать выполнение последующего промежуточного программного обеспечения и самого редуктора через next.
Простая версия метода applyMiddleware:Наконец, вам нужно объединить методы промежуточного программного обеспечения и store.dispatch, чтобы предоставить метод с именем applyMiddleware для выполнения этой задачи.
//这不是Redux最终的实现,在这里只是写出了这个方法的工作原理
function applyMiddleware (store, middlewares){
//读入middleware的函数数组
middlewares = middlewares.slice();
middlewares.reverse() ;
//保存-份副本
let dispatch = store.dispatch;
//循环middleware,将其依次覆盖到dispatch方法中,还是一种类似滚雪球的方法
middlewares.forEach (middleware => dispatch = middleware (store)(dispatch))
//到这里dispatch这个函数已经拥有了多个middleware的魔力
//返回一份store对象修改过的副本
return object.assign({}, store, { dispatch }) ;
}
store = applyMiddleware (store, [logger, crashReporter]) ;
store.dispatch (addTodo('Use Redux'));
Обратите внимание, что этот метод не является окончательной реализацией Redux, здесь просто принцип работы.После использования applyMiddleware он возвращает расширенное хранилище, а метод отправки хранилища также интегрирует два промежуточных программного обеспечения.
6. react-redux
react-redux — это официальная привязка React, предоставленная Redux, которая используется для помощи в использовании Redux в проектах React.Она характеризуется отличной производительностью, гибкостью и мощностью.
Его API довольно прост и состоит из компонента React (Provider) и метода подключения более высокого порядка.
1. Provider
Как следует из названия, роль провайдера в основном «предоставлять». Роль поставщика — это поставщик хранилища.В общем случае исходный корневой узел дерева компонентов заключен в поставщика, так что узлы всего дерева компонентов могут получить хранилище через соединение.
ReactDOM.render (
<Provider store={store}>
<MyRootComponent />
</ Provider>,
)
2. connect
connect — это метод, используемый для «соединения» хранилища и компонента. Его обычное использование выглядит следующим образом.
import { add } from ' actions';
function mapStateToProps (state) (
return {
num: state.num
};
}
function mapDispatchToProps (dispatch)
return {
onBtnClick() {
dispatch(add())
}
}
}
function Counter(props) {
return (
<p>
{props.num}
<button onClick={props.onBtnClick}>+1</button>
</p>
)
}
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
В этом примере мы подключаем компонент Counter к хранилищу через соединение, получаем информацию о количестве из хранилища и запускаем метод добавления в хранилище при нажатии кнопки (добавить — это создатель действия, а результат выполнения — действие). .
connet — это функция высокого порядка, которая получает 3 параметра mapStateToProps, mapDispatchToProps и mergeProps и возвращает энхансер.Излишне говорить, что роль энхансера определяет поведение возвращаемого компонента-контейнера, а поведение энхансера определяется метод подключения. Ниже сначала кратко объясните функции трех его параметров при вызове connect.
mapStateToProps
Для mapStateToProps требуется метод, который получает состояние параметра (то есть результат сохранения getState()) и возвращает простой объект JavaScript, содержимое которого будет объединено с конечным компонентом отображения. Проще говоря, mapStateToProps — это процесс выбора и вычисления данных, необходимых для отображения компонента, из глобальных данных состояния, то есть сопоставление состояния со свойствами компонента, как следует из названия его параметра: «mapstatetoprops». Этот метод будет вызываться при изменении начального состояния и вычислении результата, а результат будет использоваться как свойство элемента управления отображением, влияющее на его поведение. Эта часть свойств элемента управления называется stateProps.
mapDispatchToProps
Стиль именования mapDispatchToProps аналогичен первому параметру, нетрудно сделать вывод, что его функция — «отправлять карту в реквизит», то есть он получает параметр dispatch (который является методом отправки хранилища) и возвращает обычный объект JavaScript, и содержимое объекта будет включено в окончательный компонент презентации. Соответствуя mapStateToProps, он обычно используется для создания свойств данных, а mapDispatchToProps обычно используется для создания свойств поведения, то есть типичного обратного вызова, такого как onDoSth, который называется dispatchProps.
Компоненты дисплея и контейнера
Прежде всего, нам нужно ввести два понятия: презентационный компонент и контейнерный компонент. Все компоненты React можно разделить на эти два компонента, как следует из названия, первый фокусируется на представлении интерфейса, а второй предоставляет контейнер для первого. Следующие особенности помогут нам более четко различать эти два понятия.
Компоненты дисплея
- Позаботьтесь о том, как выглядит ваше приложение.
- Может содержать презентационные или контейнерные компоненты и часто содержит узлы DOM и информацию о стиле, принадлежащую самому компоненту.
- Вложение часто разрешается через this.props.children.
- Никаких зависимостей от остальной части приложения (например, действий и хранилищ Flux).
- Не указывает, как данные загружаются или изменяются.
- Получайте данные и поведение (функция обратного вызова) только через реквизиты.
- Редко содержит собственное состояние (state), если есть, то это должно быть состояние интерфейса, а не данные.
- Обычно записывается как функциональные компоненты, если вам не нужно включать состояние, обработчики жизненного цикла или оптимизацию производительности.
- Типичные примеры: Страница, Боковая панель, История, Информация о пользователе, Список.
компонент контейнера
- Позаботьтесь о том, как работает приложение.
- Может содержать презентационные или контейнерные компоненты, но обычно не содержит DOM-узлы (за исключением обертки div) и, конечно же, не содержит информации о стилях.
- Предоставлять данные и поведение (функции обратного вызова) для компонентов представления или других компонентов-контейнеров;
- Вызовите действие Flux и предоставьте его как функцию обратного вызова компоненту презентации.
- Часто с состоянием, выступая в качестве источника данных.
- Часто нет необходимости реализовывать вручную, но он генерируется компонентами более высокого порядка, такими как connect(), предоставляемый react-redux, createContainer(), предоставляемый Relay, и Container.create(), предоставляемый FluxUtils.
- Типичные примеры: UserPage, FollowedUserList.
Какая польза от этого?
Как только компоненты будут четко разделены по обязанностям, интерфейс и логика приложения станут более понятными.
Во-вторых, это различие помогает нам лучше повторно использовать компоненты: компоненты представления лучше подходят для повторного использования, и они могут стать различными компонентами-контейнерами, оборачивая разные источники данных. Например, Usrli можно упаковать в Followeduserist и FollowUserList соответственно, и нужно только реализовать логику для получения данных userList.
В конце концов, это дает нам возможность отображать интерфейс без логики — просто собрать компоненты дисплея, а затем предоставить им мок-данные, которых достаточно, чтобы завершить всю картину интерфейса.
После приведенного выше введения нетрудно обнаружить, что компоненты контейнера здесь — это компоненты, обрабатываемые функцией результата подключения в проекте на основе react-redux, а компоненты отображения — это те компоненты, которые передаются в качестве параметров или формы другие компоненты дисплея. Порядок организации поведения соединения в проекте аналогичен тому, как организовать в проекте компоненты отображения и компоненты-контейнеры.
Организация различных типов компонентов
Ниже описано, как разумно организовать компоненты представления и компоненты-контейнеры.
Во-первых, максимально строить приложение через чистые компоненты отображения (кроме корневой ноды), а данные и поведение всех компонентов получать от их родительских нод через пропсы. Тогда вы вскоре столкнетесь с проблемой, упомянутой ранее: большое количество контента должно передаваться вниз слой за слоем для использования конечными узлами. Настало время представить компоненты контейнера. Глядя на поведение передачи свойств слой за слоем, для промежуточного компонента, если некоторые данные используются только для передачи его дочерним узлам, он их не использует. Каждый раз, когда данные, требуемые его дочерними узлами, изменяются, его реквизиты должны модифицироваться соответствующим образом, чтобы адаптироваться к изменениям, поэтому эти данные не должны предоставляться им дочерним узлам. Новый компонент-контейнер генерируется путем подключения дочернего узла, который напрямую получает данные из хранилища и предоставляет их дочернему узлу, благодаря чему промежуточному компоненту не нужно передавать данные, от которых он не зависит. Это процесс непрерывной итеративной оптимизации, повторение таких шагов может помочь нам найти места, куда следует вставлять компоненты контейнера, и сделать структуру приложения все более и более разумной.
7. Оптимизация производительности
При разработке веб-приложений производительность всегда является темой, которой уделяется много внимания. Для проектов React большую часть времени не нужно учитывать проблемы производительности, что является преимуществом алгоритмов React Virtual DOM и Diff. Однако, когда приложение более сложное или поток данных большой, дерево Vitrual DOM перегенерируется и сравнение выполняется только методом рендеринга всех компонентов, этот процесс становится более трудоемким и оптимизация неизбежна.
Принцип оптимизации
- Избегайте преждевременной оптимизации
- Сосредоточьтесь на узком месте
- анализ производительности
- Избегайте ненужных рендеров
- Разумно разделенные компоненты
- неизменяемые данные
- Используйте состояние и реквизиты с умом
- Разумное использование отличных продуктов сообщества
Эта статья организована в [полный стек React], если есть какие-либо ошибки, пожалуйста, не стесняйтесь 😄
Для более интересного контента, пожалуйста, обратите внимание на мой паблик [Небесные награды за усердие Льюис]