SlideShare una empresa de Scribd logo
1 de 49
Descargar para leer sin conexión
React + Redux
Best practices
Борис Стринжа
Front-End Developer в Clickky
1. Create-react-app tool
1. Smart and Dumb components
2. Stateful and Stateless components
3. Binding
4. ShouldComponentUpdate
5. propTypes
6. Ducks pattern
7. Memoization (reselect)
8. Middlewares
React + Redux. Best practices
План
Почему мы используем
React?
React + Redux. Best practices
React + Redux. Best practices
Create React apps with no build configuration.
npm install -g create-react-app
create-react-app my-app
cd my-app/
npm start
React + Redux. Best practices
React + Redux. Best practices
To get started, edit src/App.js and save to reload
React + Redux. Best practices
package.json
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^15.4.2",
"react-dom": "^15.4.2"
},
"devDependencies": {
"react-scripts": "0.9.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
React + Redux. Best practices
npm run eject
Note: this is a one-way operation. Once you eject,
you can’t go back!
React + Redux. Best practices
Smart and Dumb
components
пример Dumb component
React + Redux. Best practices
пример Smart component
React + Redux. Best practices
Dumb
import React from 'react';
export default class Dumb extends React.Component {
selectNotificationItem = () => {
const {id} = this.props;
this.props.selectItem(id);
}
render () {
const {text, time} = this.props;
return (
<div className="item">
<span className="item__time">{time}</span>
<p className="item__text" onClick={this.selectNotificationItem}>{text}</p>
</div>
);
}
}
React + Redux. Best practices
<div className="list">
{list.map(item => {
return (
<Dumb
key={item.id}
id={item.id}
time={item.time}
text={item.text}
selectItem={this.handleSelectItem}
/>
);
})}
</div>
List.js
React + Redux. Best practices
Smartimport React from 'react';
import {connect} from 'react-redux';
import './App.css';
import Dumb from 'components/Dumb';
import {getNotificationsList, selectItem} from 'actions/notificatios';
class App extends React.Component {
componentWillMount() {
this.props.getNotificationsList();
}
handleSelectItem = (id) => {
this.props.selectItem(id);
}
render() {
const {list} = this.props;
return (
<div className="list">
{list.map(item => {
return (
<Dumb key={item.id} id={item.id} time={item.time} text={item.text} selectItem={this.handleSelectItem} />
);
})}
</div>
);
}
}
const mapStateToProps = (state) => ({
list:state.notifications.list
});
export default connect(mapStateToProps, {
getNotificationsList,
selectItem
})(App);
React + Redux. Best practices
Глупые компоненты:
1. Не зависят от остальной части приложения, например от redux actions или stores
2. Получают данные и колбэки исключительно через props
3. Имеют свой css файл
4. Изредка имеют свой state
5. Могут использовать другие глупые компоненты
Умные компоненты:
1. Оборачивает один или несколько глупых или умных компонентов
2. Хранит состояние стора и пробрасывает его как объекты в глупые компоненты
3. Вызывает redux actions и обеспечивает ими глупые компоненты в виде колбэков
4. Никогда не имеют собственных стилей
5. Редко сами выдают DOM, используйте глупые компоненты для макета
React + Redux. Best practices
Stateful and Stateless
components
React + Redux. Best practices
Stateful
import React from 'react';
export default class Counter extends React.Component {
state = {
count: 1
};
componentWillMount() {
this.setState({
count: this.state.count + 1
});
}
render () {
const {count} = this.state;
const {text} = this.props;
return (
<div className="item">
<span className="item__count">{count}</span>
<p className="item__text">{text}</p>
</div>
);
}
}
React + Redux. Best practices
Stateless
import React from 'react';
const Counter = ({addCount, text, count}) => {
return (
<div className="item">
<span className="item__count" onClick={addCount}>
{count}
</span>
<p className="item__text">{text}</p>
</div>
);
}
export default Counter;
React + Redux. Best practices
Binding
React + Redux. Best practices
Bind in Render
handleSelectItem(id) {
this.props.selectItem(id);
}
render() {
const {list} = this.props;
return (
<div className="list">
{list.map(item => {
return (
<div className="list__item" onClick={this.handleSelectItem.bind(this, item.id)}>
{item.text}
</div>
);
})}
</div>
);
}
handleSelectItem(id) {
this.props.selectItem(id);
}
render() {
const {list} = this.props;
return (
<div className="list">
{list.map(item => {
return (
<div className="list__item" onClick={(item) => this.handleSelectItem(item.id)}>
{item.text}
</div>
);
})}
</div>
);
}
React + Redux. Best practices
Arrow Function in Render
Bind in Constructor
constructor(props) {
super(props);
this.handleSelectItem = this.handleSelectItem.bind(this);
}
handleSelectItem(id) {
this.props.selectItem(id);
}
render() {
const {list} = this.props;
return (
<div className="list">
{list.map(item => {
return (
<div key={item.id} className="list__item">
<Dumb
id={item.id}
text={item.text}
selectItem={this.handleSelectItem}
/>
</div>
);
})}
</div>
);
}
React + Redux. Best practices
Arrow Function in Class Property
handleSelectItem = (id) => {
this.props.selectItem(id);
}
render() {
const {list} = this.props;
return (
<div className="list">
{list.map(item => {
return (
<div key={item.id} className="list__item">
<Dumb
id={item.id}
text={item.text}
selectItem={this.handleSelectItem}
/>
</div>
);
})}
</div>
);
}
React + Redux. Best practices
shouldComponentUpdate
React + Redux. Best practices
shouldComponentUpdate(nextProps, nextState) {
if (this.props.value !== nextProps.value) {
return true;
}
if (this.state.count !== nextState.count) {
return true;
}
return false;
}
component
React + Redux. Best practices
propTypes
export default class Activation extends React.Component {
static propTypes = {
query: React.PropTypes.object,
activatePublisher: React.PropTypes.func,
activateAdvertiser: React.PropTypes.func,
setActivationStatus: React.PropTypes.func,
isFetching: React.PropTypes.bool.isRequired,
activationStatus: React.PropTypes.bool.isRequired,
language: React.PropTypes.string
};
render() {
const {query} = this.props;
return(
<div></div>
);
}
}
components/Activation.js
React + Redux. Best practices
Console
React + Redux. Best practices
Ducks pattern
import {
NOTIFICATIONS_GET_LIST_REQUEST,
NOTIFICATIONS_GET_LIST_SUCCESS,
NOTIFICATIONS_GET_LIST_FAILURE,
NOTIFICATIONS_SELECT_ITEM
} from 'constants';
export function getNotificationsList() {
return {
types: [NOTIFICATIONS_GET_LIST_REQUEST, NOTIFICATIONS_GET_LIST_SUCCESS, NOTIFICATIONS_GET_LIST_FAILURE],
url: '/api/v1.0/notifications'
}
}
export function selectItem(data) {
return {
type: NOTIFICATIONS_SELECT_ITEM,
data
}
}
actions/notifications.js
React + Redux. Best practices
import {
NOTIFICATIONS_GET_LIST_REQUEST,
NOTIFICATIONS_GET_LIST_SUCCESS,
NOTIFICATIONS_GET_LIST_FAILURE,
NOTIFICATIONS_SELECT_ITEM
} from 'constants';
const initialState = {
list: [],
loading: false,
selected: null
};
export default (state = initialState, action = {}) => {
switch (action.type) {
case NOTIFICATIONS_GET_LIST_REQUEST:
return {
...state,
loading: true
};
case NOTIFICATIONS_GET_LIST_SUCCESS:
return {
...state,
list: actions.result,
loading: false
};
case NOTIFICATIONS_GET_LIST_FAILURE:
return {
...state,
loading: false
};
case NOTIFICATIONS_SELECT_ITEM:
return {
...state,
selected: action.data
};
default:
return state;
}
};
reducers/notifications.js
React + Redux. Best practices
export const NOTIFICATIONS_GET_LIST_REQUEST = 'NOTIFICATIONS_GET_LIST_REQUEST';
export const NOTIFICATIONS_GET_LIST_SUCCESS = 'NOTIFICATIONS_GET_LIST_SUCCESS';
export const NOTIFICATIONS_GET_LIST_FAILURE = 'NOTIFICATIONS_GET_LIST_FAILURE';
export const NOTIFICATIONS_SELECT_ITEM = 'NOTIFICATIONS_SELECT_ITEM';
constants/index.js
React + Redux. Best practices
// Actions
const GET_LIST_REQUEST = 'my-app/notifications/GET_LIST_REQUEST';
const GET_LIST_SUCCESS = 'my-app/notifications/GET_LIST_SUCCESS';
const GET_LIST_FAILURE = 'my-app/notifications/GET_LIST_FAILURE';
const SELECT_ITEM = 'my-app/notifications/SELECT_ITEM';
// Reducer
const initialState = {
list: [],
loading: false,
selected: null
};
export default function reducer(state = initialState, action = {}) => {
switch (action.type) {
case NOTIFICATIONS_GET_LIST_REQUEST:
return {
...state,
loading: true
};
case NOTIFICATIONS_GET_LIST_SUCCESS:
return {
...state,
list: actions.result,
loading: false
};
React + Redux. Best practices
modules/notifications.js
case NOTIFICATIONS_GET_LIST_FAILURE:
return {
...state,
loading: false
};
case NOTIFICATIONS_SELECT_ITEM:
return {
...state,
selected: action.data
};
default:
return state;
}
};
// Actions Creators
export function getNotificationsList() {
return {
types: [GET_LIST_REQUEST, GET_LIST_SUCCESS, GET_LIST_FAILURE],
url: '/api/v1.0/notifications'
}
}
export function selectItem(data) {
return {
type: SELECT_ITEM,
data
}
}
React + Redux. Best practices
1. MUST export default a function called reducer()
2. MUST export its action creators as functions
3. MUST have action types in the form
npm-module-or-app/reducer/ACTION_TYPE
4. MAY export its action types as UPPER_CASE, if an
external reducer needs to listen for them, or if it is a
published reusable library
React + Redux. Best practices
Requirements
Memoization
Memoization is an optimization technique used
primarily to speed up computer programs by storing
the results of expensive function calls and returning
the cached result when the same inputs occur again
React + Redux. Best practices
Reselect
import { createSelector } from 'reselect';
import {beautifyDate} from 'utils/date';
const data = (state) => state.notifications.data;
export const notificationsSelector = createSelector(
[data],
(notifications) => {
return notifications.reduce((list, item) => {
const title = beautifyDate(item.date, 'DD.MM.YYYY');
if (!list[title]) {
list[title] = [{...item}];
} else {
list[title] = [...list[title], {...item}];
}
return list;
}, {});
}
);
selectors/notifications.js
React + Redux. Best practices
import {notificationsSelector} from 'selectors/notifications';
const mapStateToProps = (state) => ({
list: notificationsSelector(state)
});
export default connect(mapStateToProps, {})(List);
containers/Notifications/index.js
React + Redux. Best practices
React + Redux. Best practices
Basic middleware
const customMiddleware = store => next => action => {
if (action.type !== 'custom') {
return next(action);
}
}
export default customMiddleware;
React + Redux. Best practices
store/index.js
import { createStore, applyMiddleware, } from 'redux'
import reducer from './reducer'
import customMiddleware from './customMiddleware'
const store = createStore(
reducer,
applyMiddleware(customMiddleware)
);
React + Redux. Best practices
middleware/apiMiddleware.js
import { push } from 'react-router-redux';
const apiMiddleware = (store) => (next) => (action) => {
const { url, types, method, body, ...rest } = action;
const { dispatch } = store;
if (!types) {
return next(action);
}
const [REQUEST, SUCCESS, FAILURE] = types;
next({...rest, type: REQUEST});
return fetch(url, {
method: method || 'GET',
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(body)
}).then((res) => {
if (res.status >= 200 && res.status < 300) {
return res.json();
} else {
next({...rest, error: res.statusText, type: FAILURE});
if (res.status === 401) {
window.localStorage.removeItem('user');
dispatch(push('/login'));
}
return Promise.reject(new Error(res.statusText));
}
}).then(({result, ...rest}) => {
next({...rest, result, type: SUCCESS});
});
};
export default apiMiddleware;
export function getNotificationsList(data) {
return {
types: [NOTIFICATIONS_GET_LIST_REQUEST, NOTIFICATIONS_GET_LIST_SUCCESS,
NOTIFICATIONS_GET_LIST_FAILURE],
url: '/api/v1.0/notifications',
method: POST
body: data
}
}
actions/notifications.js
React + Redux. Best practices
Делаем небольшие dumb компоненты, не боимся использовать
connect, в пользу читаемости кода
Для простого рендера используем stateless компоненты
Всегда используем propTypes
Контролируем перерендер с помощью shouldComponentUpdate
Используем мемоизацию с помощью reselect
Используем middleware
Выводы
React + Redux. Best practices
Вопросы
49

Más contenido relacionado

La actualidad más candente

Rediscovering Spring with Spring Boot(1)
Rediscovering Spring with Spring Boot(1)Rediscovering Spring with Spring Boot(1)
Rediscovering Spring with Spring Boot(1)
Gunith Devasurendra
 

La actualidad más candente (20)

React JS - A quick introduction tutorial
React JS - A quick introduction tutorialReact JS - A quick introduction tutorial
React JS - A quick introduction tutorial
 
Rediscovering Spring with Spring Boot(1)
Rediscovering Spring with Spring Boot(1)Rediscovering Spring with Spring Boot(1)
Rediscovering Spring with Spring Boot(1)
 
Introduction to React
Introduction to ReactIntroduction to React
Introduction to React
 
React js for beginners
React js for beginnersReact js for beginners
React js for beginners
 
NEXT.JS
NEXT.JSNEXT.JS
NEXT.JS
 
Build web apps with react js
Build web apps with react jsBuild web apps with react js
Build web apps with react js
 
React JS: A Secret Preview
React JS: A Secret PreviewReact JS: A Secret Preview
React JS: A Secret Preview
 
React + Redux Introduction
React + Redux IntroductionReact + Redux Introduction
React + Redux Introduction
 
Spring Core
Spring CoreSpring Core
Spring Core
 
NestJS
NestJSNestJS
NestJS
 
introduction to Vue.js 3
introduction to Vue.js 3 introduction to Vue.js 3
introduction to Vue.js 3
 
React lecture
React lectureReact lecture
React lecture
 
reactJS
reactJSreactJS
reactJS
 
Presentation1.pptx
Presentation1.pptxPresentation1.pptx
Presentation1.pptx
 
React for Beginners
React for BeginnersReact for Beginners
React for Beginners
 
Spring Boot and REST API
Spring Boot and REST APISpring Boot and REST API
Spring Boot and REST API
 
Introduction to react_js
Introduction to react_jsIntroduction to react_js
Introduction to react_js
 
Introduction to React JS for beginners
Introduction to React JS for beginners Introduction to React JS for beginners
Introduction to React JS for beginners
 
React
React React
React
 
Introduction to VueJS & Vuex
Introduction to VueJS & VuexIntroduction to VueJS & Vuex
Introduction to VueJS & Vuex
 

Similar a React + Redux. Best practices

Reactive.architecture.with.Angular
Reactive.architecture.with.AngularReactive.architecture.with.Angular
Reactive.architecture.with.Angular
Evan Schultz
 
[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
洪 鹏发
 

Similar a React + Redux. Best practices (20)

Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
 
Intro to React | DreamLab Academy
Intro to React | DreamLab AcademyIntro to React | DreamLab Academy
Intro to React | DreamLab Academy
 
React redux
React reduxReact redux
React redux
 
React, Redux and es6/7
React, Redux and es6/7React, Redux and es6/7
React, Redux and es6/7
 
Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3 Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applications
 
Reactивная тяга
Reactивная тягаReactивная тяга
Reactивная тяга
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & Redux
 
Using React, Redux and Saga with Lottoland APIs
Using React, Redux and Saga with Lottoland APIsUsing React, Redux and Saga with Lottoland APIs
Using React, Redux and Saga with Lottoland APIs
 
Introducing Vuex in your project
Introducing Vuex in your projectIntroducing Vuex in your project
Introducing Vuex in your project
 
State manager in Vue.js, from zero to Vuex
State manager in Vue.js, from zero to VuexState manager in Vue.js, from zero to Vuex
State manager in Vue.js, from zero to Vuex
 
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
 
MeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenmentMeetJS Summit 2016: React.js enlightenment
MeetJS Summit 2016: React.js enlightenment
 
Recompacting your react application
Recompacting your react applicationRecompacting your react application
Recompacting your react application
 
Ngrx slides
Ngrx slidesNgrx slides
Ngrx slides
 
Reactive.architecture.with.Angular
Reactive.architecture.with.AngularReactive.architecture.with.Angular
Reactive.architecture.with.Angular
 
Server side rendering with React and Symfony
Server side rendering with React and SymfonyServer side rendering with React and Symfony
Server side rendering with React and Symfony
 
JS Fest 2019. Glenn Reyes. With great power comes great React hooks!
JS Fest 2019. Glenn Reyes. With great power comes great React hooks!JS Fest 2019. Glenn Reyes. With great power comes great React hooks!
JS Fest 2019. Glenn Reyes. With great power comes great React hooks!
 
Workshop 19: ReactJS Introduction
Workshop 19: ReactJS IntroductionWorkshop 19: ReactJS Introduction
Workshop 19: ReactJS Introduction
 
[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
 

Más de Clickky

Más de Clickky (20)

Case-study: How to market ICO with success.
Case-study: How to market ICO with success. Case-study: How to market ICO with success.
Case-study: How to market ICO with success.
 
Clickhouse
ClickhouseClickhouse
Clickhouse
 
Лучшие кейсы и практики монетизации мобильного трафика
Лучшие кейсы и практики монетизации мобильного трафикаЛучшие кейсы и практики монетизации мобильного трафика
Лучшие кейсы и практики монетизации мобильного трафика
 
Case study. Advertisers success in mobile economy
Case study. Advertisers success in mobile economyCase study. Advertisers success in mobile economy
Case study. Advertisers success in mobile economy
 
#MBC2016 Dan Ekstein, Supersonic Finding the Perfect Balance Between Rewarded...
#MBC2016 Dan Ekstein, Supersonic Finding the Perfect Balance Between Rewarded...#MBC2016 Dan Ekstein, Supersonic Finding the Perfect Balance Between Rewarded...
#MBC2016 Dan Ekstein, Supersonic Finding the Perfect Balance Between Rewarded...
 
#MBC2016 Кирилл Софронов, Remerge: Ретаргетинг в мобильных приложениях: опыт ...
#MBC2016 Кирилл Софронов, Remerge: Ретаргетинг в мобильных приложениях: опыт ...#MBC2016 Кирилл Софронов, Remerge: Ретаргетинг в мобильных приложениях: опыт ...
#MBC2016 Кирилл Софронов, Remerge: Ретаргетинг в мобильных приложениях: опыт ...
 
#MBC2016 Илья Лагутин, Aitarget: Как эффективно продвигать мобильные приложен...
#MBC2016 Илья Лагутин, Aitarget: Как эффективно продвигать мобильные приложен...#MBC2016 Илья Лагутин, Aitarget: Как эффективно продвигать мобильные приложен...
#MBC2016 Илья Лагутин, Aitarget: Как эффективно продвигать мобильные приложен...
 
#MBC2016 Mark Ten, Sports.ru: Programmatic monetization of mobile apps
#MBC2016 Mark Ten, Sports.ru: Programmatic monetization of mobile apps#MBC2016 Mark Ten, Sports.ru: Programmatic monetization of mobile apps
#MBC2016 Mark Ten, Sports.ru: Programmatic monetization of mobile apps
 
#MBC2016 Dvir Doron, Cedato: Mobile video - the new growth engine
#MBC2016 Dvir Doron, Cedato: Mobile video - the new growth engine #MBC2016 Dvir Doron, Cedato: Mobile video - the new growth engine
#MBC2016 Dvir Doron, Cedato: Mobile video - the new growth engine
 
#MBC2016 Bashir Modanov, NewBornTown: Globalized mobile ecosystem
#MBC2016 Bashir Modanov, NewBornTown: Globalized mobile ecosystem#MBC2016 Bashir Modanov, NewBornTown: Globalized mobile ecosystem
#MBC2016 Bashir Modanov, NewBornTown: Globalized mobile ecosystem
 
Как настроить B2B продажи за границей из Украины
Как настроить B2B продажи за границей из УкраиныКак настроить B2B продажи за границей из Украины
Как настроить B2B продажи за границей из Украины
 
Как выжать еще больше из мобильного трафика?
Как выжать еще больше из мобильного трафика?Как выжать еще больше из мобильного трафика?
Как выжать еще больше из мобильного трафика?
 
AdExchange mediakit
AdExchange mediakitAdExchange mediakit
AdExchange mediakit
 
Поймай меня, если сможешь
Поймай меня, если сможешьПоймай меня, если сможешь
Поймай меня, если сможешь
 
WannaBiz Fund
WannaBiz FundWannaBiz Fund
WannaBiz Fund
 
AdExchange mediakit
AdExchange mediakitAdExchange mediakit
AdExchange mediakit
 
Clickky fraud presentation at Kinza 2015
Clickky fraud presentation at Kinza 2015Clickky fraud presentation at Kinza 2015
Clickky fraud presentation at Kinza 2015
 
МАРКЕТИНГОВЫЕ ЦЕЛИ И ЗАКУПКА ТРАФИКА
МАРКЕТИНГОВЫЕ ЦЕЛИ И ЗАКУПКА ТРАФИКАМАРКЕТИНГОВЫЕ ЦЕЛИ И ЗАКУПКА ТРАФИКА
МАРКЕТИНГОВЫЕ ЦЕЛИ И ЗАКУПКА ТРАФИКА
 
The trends of mobile in e-commerce, Mobilimes Serg Korneev
The trends of mobile in e-commerce, Mobilimes Serg KorneevThe trends of mobile in e-commerce, Mobilimes Serg Korneev
The trends of mobile in e-commerce, Mobilimes Serg Korneev
 
Инвестиции в mobile marketing, Алексей Тельнов iTech Capital, Mobile Beach Co...
Инвестиции в mobile marketing, Алексей Тельнов iTech Capital, Mobile Beach Co...Инвестиции в mobile marketing, Алексей Тельнов iTech Capital, Mobile Beach Co...
Инвестиции в mobile marketing, Алексей Тельнов iTech Capital, Mobile Beach Co...
 

Último

%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 

Último (20)

%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 

React + Redux. Best practices

  • 1. React + Redux Best practices
  • 3. 1. Create-react-app tool 1. Smart and Dumb components 2. Stateful and Stateless components 3. Binding 4. ShouldComponentUpdate 5. propTypes 6. Ducks pattern 7. Memoization (reselect) 8. Middlewares React + Redux. Best practices План
  • 5. React + Redux. Best practices
  • 6. Create React apps with no build configuration. npm install -g create-react-app create-react-app my-app cd my-app/ npm start React + Redux. Best practices
  • 7. React + Redux. Best practices
  • 8. To get started, edit src/App.js and save to reload React + Redux. Best practices
  • 9. package.json { "name": "my-app", "version": "0.1.0", "private": true, "dependencies": { "react": "^15.4.2", "react-dom": "^15.4.2" }, "devDependencies": { "react-scripts": "0.9.5" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" } } React + Redux. Best practices
  • 10. npm run eject Note: this is a one-way operation. Once you eject, you can’t go back! React + Redux. Best practices
  • 12. пример Dumb component React + Redux. Best practices
  • 13. пример Smart component React + Redux. Best practices
  • 14. Dumb import React from 'react'; export default class Dumb extends React.Component { selectNotificationItem = () => { const {id} = this.props; this.props.selectItem(id); } render () { const {text, time} = this.props; return ( <div className="item"> <span className="item__time">{time}</span> <p className="item__text" onClick={this.selectNotificationItem}>{text}</p> </div> ); } } React + Redux. Best practices
  • 15. <div className="list"> {list.map(item => { return ( <Dumb key={item.id} id={item.id} time={item.time} text={item.text} selectItem={this.handleSelectItem} /> ); })} </div> List.js React + Redux. Best practices
  • 16. Smartimport React from 'react'; import {connect} from 'react-redux'; import './App.css'; import Dumb from 'components/Dumb'; import {getNotificationsList, selectItem} from 'actions/notificatios'; class App extends React.Component { componentWillMount() { this.props.getNotificationsList(); } handleSelectItem = (id) => { this.props.selectItem(id); } render() { const {list} = this.props; return ( <div className="list"> {list.map(item => { return ( <Dumb key={item.id} id={item.id} time={item.time} text={item.text} selectItem={this.handleSelectItem} /> ); })} </div> ); } } const mapStateToProps = (state) => ({ list:state.notifications.list }); export default connect(mapStateToProps, { getNotificationsList, selectItem })(App); React + Redux. Best practices
  • 17. Глупые компоненты: 1. Не зависят от остальной части приложения, например от redux actions или stores 2. Получают данные и колбэки исключительно через props 3. Имеют свой css файл 4. Изредка имеют свой state 5. Могут использовать другие глупые компоненты Умные компоненты: 1. Оборачивает один или несколько глупых или умных компонентов 2. Хранит состояние стора и пробрасывает его как объекты в глупые компоненты 3. Вызывает redux actions и обеспечивает ими глупые компоненты в виде колбэков 4. Никогда не имеют собственных стилей 5. Редко сами выдают DOM, используйте глупые компоненты для макета React + Redux. Best practices
  • 18. Stateful and Stateless components React + Redux. Best practices
  • 19. Stateful import React from 'react'; export default class Counter extends React.Component { state = { count: 1 }; componentWillMount() { this.setState({ count: this.state.count + 1 }); } render () { const {count} = this.state; const {text} = this.props; return ( <div className="item"> <span className="item__count">{count}</span> <p className="item__text">{text}</p> </div> ); } } React + Redux. Best practices
  • 20. Stateless import React from 'react'; const Counter = ({addCount, text, count}) => { return ( <div className="item"> <span className="item__count" onClick={addCount}> {count} </span> <p className="item__text">{text}</p> </div> ); } export default Counter; React + Redux. Best practices
  • 22. React + Redux. Best practices Bind in Render handleSelectItem(id) { this.props.selectItem(id); } render() { const {list} = this.props; return ( <div className="list"> {list.map(item => { return ( <div className="list__item" onClick={this.handleSelectItem.bind(this, item.id)}> {item.text} </div> ); })} </div> ); }
  • 23. handleSelectItem(id) { this.props.selectItem(id); } render() { const {list} = this.props; return ( <div className="list"> {list.map(item => { return ( <div className="list__item" onClick={(item) => this.handleSelectItem(item.id)}> {item.text} </div> ); })} </div> ); } React + Redux. Best practices Arrow Function in Render
  • 24. Bind in Constructor constructor(props) { super(props); this.handleSelectItem = this.handleSelectItem.bind(this); } handleSelectItem(id) { this.props.selectItem(id); } render() { const {list} = this.props; return ( <div className="list"> {list.map(item => { return ( <div key={item.id} className="list__item"> <Dumb id={item.id} text={item.text} selectItem={this.handleSelectItem} /> </div> ); })} </div> ); } React + Redux. Best practices
  • 25. Arrow Function in Class Property handleSelectItem = (id) => { this.props.selectItem(id); } render() { const {list} = this.props; return ( <div className="list"> {list.map(item => { return ( <div key={item.id} className="list__item"> <Dumb id={item.id} text={item.text} selectItem={this.handleSelectItem} /> </div> ); })} </div> ); } React + Redux. Best practices
  • 27. shouldComponentUpdate(nextProps, nextState) { if (this.props.value !== nextProps.value) { return true; } if (this.state.count !== nextState.count) { return true; } return false; } component React + Redux. Best practices
  • 29. export default class Activation extends React.Component { static propTypes = { query: React.PropTypes.object, activatePublisher: React.PropTypes.func, activateAdvertiser: React.PropTypes.func, setActivationStatus: React.PropTypes.func, isFetching: React.PropTypes.bool.isRequired, activationStatus: React.PropTypes.bool.isRequired, language: React.PropTypes.string }; render() { const {query} = this.props; return( <div></div> ); } } components/Activation.js React + Redux. Best practices
  • 30. Console React + Redux. Best practices
  • 32. import { NOTIFICATIONS_GET_LIST_REQUEST, NOTIFICATIONS_GET_LIST_SUCCESS, NOTIFICATIONS_GET_LIST_FAILURE, NOTIFICATIONS_SELECT_ITEM } from 'constants'; export function getNotificationsList() { return { types: [NOTIFICATIONS_GET_LIST_REQUEST, NOTIFICATIONS_GET_LIST_SUCCESS, NOTIFICATIONS_GET_LIST_FAILURE], url: '/api/v1.0/notifications' } } export function selectItem(data) { return { type: NOTIFICATIONS_SELECT_ITEM, data } } actions/notifications.js React + Redux. Best practices
  • 33. import { NOTIFICATIONS_GET_LIST_REQUEST, NOTIFICATIONS_GET_LIST_SUCCESS, NOTIFICATIONS_GET_LIST_FAILURE, NOTIFICATIONS_SELECT_ITEM } from 'constants'; const initialState = { list: [], loading: false, selected: null }; export default (state = initialState, action = {}) => { switch (action.type) { case NOTIFICATIONS_GET_LIST_REQUEST: return { ...state, loading: true }; case NOTIFICATIONS_GET_LIST_SUCCESS: return { ...state, list: actions.result, loading: false }; case NOTIFICATIONS_GET_LIST_FAILURE: return { ...state, loading: false }; case NOTIFICATIONS_SELECT_ITEM: return { ...state, selected: action.data }; default: return state; } }; reducers/notifications.js React + Redux. Best practices
  • 34. export const NOTIFICATIONS_GET_LIST_REQUEST = 'NOTIFICATIONS_GET_LIST_REQUEST'; export const NOTIFICATIONS_GET_LIST_SUCCESS = 'NOTIFICATIONS_GET_LIST_SUCCESS'; export const NOTIFICATIONS_GET_LIST_FAILURE = 'NOTIFICATIONS_GET_LIST_FAILURE'; export const NOTIFICATIONS_SELECT_ITEM = 'NOTIFICATIONS_SELECT_ITEM'; constants/index.js React + Redux. Best practices
  • 35. // Actions const GET_LIST_REQUEST = 'my-app/notifications/GET_LIST_REQUEST'; const GET_LIST_SUCCESS = 'my-app/notifications/GET_LIST_SUCCESS'; const GET_LIST_FAILURE = 'my-app/notifications/GET_LIST_FAILURE'; const SELECT_ITEM = 'my-app/notifications/SELECT_ITEM'; // Reducer const initialState = { list: [], loading: false, selected: null }; export default function reducer(state = initialState, action = {}) => { switch (action.type) { case NOTIFICATIONS_GET_LIST_REQUEST: return { ...state, loading: true }; case NOTIFICATIONS_GET_LIST_SUCCESS: return { ...state, list: actions.result, loading: false }; React + Redux. Best practices modules/notifications.js
  • 36. case NOTIFICATIONS_GET_LIST_FAILURE: return { ...state, loading: false }; case NOTIFICATIONS_SELECT_ITEM: return { ...state, selected: action.data }; default: return state; } }; // Actions Creators export function getNotificationsList() { return { types: [GET_LIST_REQUEST, GET_LIST_SUCCESS, GET_LIST_FAILURE], url: '/api/v1.0/notifications' } } export function selectItem(data) { return { type: SELECT_ITEM, data } } React + Redux. Best practices
  • 37. 1. MUST export default a function called reducer() 2. MUST export its action creators as functions 3. MUST have action types in the form npm-module-or-app/reducer/ACTION_TYPE 4. MAY export its action types as UPPER_CASE, if an external reducer needs to listen for them, or if it is a published reusable library React + Redux. Best practices Requirements
  • 39. Memoization is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again React + Redux. Best practices
  • 41. import { createSelector } from 'reselect'; import {beautifyDate} from 'utils/date'; const data = (state) => state.notifications.data; export const notificationsSelector = createSelector( [data], (notifications) => { return notifications.reduce((list, item) => { const title = beautifyDate(item.date, 'DD.MM.YYYY'); if (!list[title]) { list[title] = [{...item}]; } else { list[title] = [...list[title], {...item}]; } return list; }, {}); } ); selectors/notifications.js React + Redux. Best practices
  • 42. import {notificationsSelector} from 'selectors/notifications'; const mapStateToProps = (state) => ({ list: notificationsSelector(state) }); export default connect(mapStateToProps, {})(List); containers/Notifications/index.js React + Redux. Best practices
  • 43. React + Redux. Best practices
  • 44. Basic middleware const customMiddleware = store => next => action => { if (action.type !== 'custom') { return next(action); } } export default customMiddleware; React + Redux. Best practices
  • 45. store/index.js import { createStore, applyMiddleware, } from 'redux' import reducer from './reducer' import customMiddleware from './customMiddleware' const store = createStore( reducer, applyMiddleware(customMiddleware) ); React + Redux. Best practices
  • 46. middleware/apiMiddleware.js import { push } from 'react-router-redux'; const apiMiddleware = (store) => (next) => (action) => { const { url, types, method, body, ...rest } = action; const { dispatch } = store; if (!types) { return next(action); } const [REQUEST, SUCCESS, FAILURE] = types; next({...rest, type: REQUEST}); return fetch(url, { method: method || 'GET', credentials: 'same-origin', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify(body) }).then((res) => { if (res.status >= 200 && res.status < 300) { return res.json(); } else { next({...rest, error: res.statusText, type: FAILURE}); if (res.status === 401) { window.localStorage.removeItem('user'); dispatch(push('/login')); } return Promise.reject(new Error(res.statusText)); } }).then(({result, ...rest}) => { next({...rest, result, type: SUCCESS}); }); }; export default apiMiddleware;
  • 47. export function getNotificationsList(data) { return { types: [NOTIFICATIONS_GET_LIST_REQUEST, NOTIFICATIONS_GET_LIST_SUCCESS, NOTIFICATIONS_GET_LIST_FAILURE], url: '/api/v1.0/notifications', method: POST body: data } } actions/notifications.js React + Redux. Best practices
  • 48. Делаем небольшие dumb компоненты, не боимся использовать connect, в пользу читаемости кода Для простого рендера используем stateless компоненты Всегда используем propTypes Контролируем перерендер с помощью shouldComponentUpdate Используем мемоизацию с помощью reselect Используем middleware Выводы React + Redux. Best practices