class TodoList extends React.Component {
state = {
todos: [
'Commit',
'Push'
]
}
render() {
return <ul>
{this.state.todos.map(item => {
return <li>{ todo }</li>
}
</ul>
}
}
const todos = [
'Init',
'Commit',
'Push'
]
// Начальный стейт
<ul>
<li>Commit</li>
<li>Push</li>
</ul>
// Добавлен элемент
<ul>
<li>Init</li> // <- разница начинается здесь и до конца древа
<li>Commit</li>
<li>Push</li>
</ul>
const todos = [
'Commit',
'Push',
'Merge'
]
// Начальный стейт
<ul>
<li>Commit</li>
<li>Push</li>
</ul>
// Добавлен элемент
<ul>
<li>Commit</li>
<li>Push</li>
<li>Merge</li> <- разница начинается здесь, от начала и до сих по ничего не менялось
</ul>
<li>Commit</li>
и <li>Push</li>
не менялись, однако реакт недостаточно умён чтобы это понять. Чтобы помочь ему следует воспользоваться специальным пропом key={}
. Он может быть значением любого типа, единственно требование — значение должно стабильно идентифицировать соответствующие данные.class TodoList extends React.Component {
state = {
todos: [
{ id: 0, text: 'Commit' },
{ id: 1, text: 'Push' }
]
}
render() {
return <ul>
{this.state.todos.map(item => {
return <li key={todo.id}>{ todo.text }</li>
}
</ul>
}
}
const todos = [
{ id: 2, text: 'Init' },
{ id: 0, text: 'Commit' },
{ id: 1, text: 'Push' }
]
// Начальный стейт
<ul>
<li>Commit</li> // id 0
<li>Push</li> // id 1
</ul>
// Добавлен элемент
<ul>
<li>Init</li> // id 2 новый элемент отобразится в начале
<li>Commit</li> // id 0
<li>Push</li> // id 1
</ul>
Math.random()
в качестве ключа, так вы почти гарантировано будете всегда получать нестабильные идентификаторы.const transpose = matrix => matrix[0].map((col, i) => matrix.map(row => row[i]));
const baseMatrix = [[1, 2], [3, 4], [5, 6]];
const transposedMatrix = transpose(baseMatrix);
// [ [ 1, 3, 5 ], [ 2, 4, 6 ] ]
Функция высшего порядка, в отличие от функции первого порядка, имеет один из трёх видов:
1. Один из параметров функции также является функцией и она возвращает значение.
2. Она возвращает функцию, но ни один из параметров не является функцией.
3. И первый и второй пункт: функция возвращает функцию и один из параметров является функцией.
<Component />
- так позволяет писать движок jsx, который и React его использует.<Provider>
<MyComponent />//Вот сюда Provider пробросит (запишет) новые props.
</Provider>
{
chunkStore: {},
some: {}
}
{store: store.chunkStore}
то Provider в props своего потомка пробросит такое: store: store.chunkStore. И ты будешь обращаться внутри к store, но там будет только часть chunkStore (не весь объект, а его поле).Как в юнит тестах тестить нажатие на кнопку? Или мы можем тестить только функцию-обработчик?
import * as React from 'react';
import { connect, DispatchProp } from 'react-redux';
import { connectedPropSelector } from './selectors';
interface OwnProps {
ownProp: string,
}
interface ConnectedProps {
connectedProp: string,
}
type Props = OwnProps & ConnectedProps & DispatchProp<any>;
interface State {
someKey: string,
}
class Example extends React.Component<Props, State> {
state = {
someKey: 'someValue',
};
render() {
const { ownProp, connectedProp } = this.props;
return ( /* ... */ );
}
}
const mapStateToProps = state => ({
connectedProp: connectedPropSelector(state),
});
export default connect(mapStateToProps)(Example);
element.scrollIntoView();
handleLinkClick = e => {
e.preventDefault();
const element = document.getElementById(e.target.href);
element.scrollIntoView();
};
class ArrowUp extends Component {
state = {
isVisible: false,
};
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
handleScroll = () => {
if (window.scrollY >= SOME_VALUE && !this.state.isVisible) {
this.setState({ isVisible: true });
} else if (window.scrollY < SOME_VALUE && this.state.isVisible) {
this.setState({ isVisible: false });
}
};
render() { /* ... */ }
}
Tree shaking (встряхивание дерева) — термин объединения модулей JavaScript, обозначающий статический анализ всего импортированного кода и исключение того, что на самом деле не используется.
Для более прямолинейной аналогии рассмотрим живое дерево. Дерево встряхивается, и это заставляет мертвые листья отваливаться, оставляя только живые. В основе tree shaking лежит концепция живого включения кода (live code inclusion): мы включаем части, необходимые для начала, в отличие от удаления ненужных частей в конце — устранения «мертвого кода» (dead code elimination).
Tree shaking зависит от import и export модулей ES2015. Выражения import и export составляют статическую структуру модуля приложения. Когда модули объединяются для развертывания приложения, tree shaker анализирует статическую структуру модуля, чтобы исключить неиспользуемый экспорт, уменьшив размер окончательного пакета.
ES2015 позволяет указывать явный импорт. Например, вместо импорта всей библиотеки RxJS мы можем импортировать именно то, что хотим:
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
Это отличается от динамического выражения require, используемого CommonJS или AMD. Tree shaking использует этот принцип для перемещения по зависимостям и исключения ненужных зависимостей для уменьшения размера приложения.
Принцип tree shaking не нов, но он только недавно был популяризирован с помощью сборщика rollup.js, объединяющего модули приложения. Webpack 2 также использует tree shaking. Концепция tree shaking также распространена в Angular с компиляцией AOT.