Top Banner
React.Redux.Real world. Rostislav (BABO)
53

React. Redux. Real world.

Apr 13, 2017

Download

Software

Rost Galkin
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: React. Redux. Real world.

React.Redux.Real world.Rostislav (BABO)

Page 2: React. Redux. Real world.

BABO2

Page 3: React. Redux. Real world.

3

Page 4: React. Redux. Real world.

4

Page 5: React. Redux. Real world.

5

Page 6: React. Redux. Real world.

6

Page 7: React. Redux. Real world.

FRONTEND7

Page 8: React. Redux. Real world.

Webpack

React, Redux

CSS Modules

8

Page 9: React. Redux. Real world.

React9

Page 10: React. Redux. Real world.

Бесконечные списки

Screen gif

10

Page 11: React. Redux. Real world.

React-ingrid

11Отображать только те элементы, которые умещаются на экране

Page 12: React. Redux. Real world.

Universal rendering

const html = ReactDOM.renderToString(<App data={data} />)

res.send(html)

12

Блокирующий вызов

Page 13: React. Redux. Real world.

Future

React-dom-stream

res.write(`<!DOCTYPE html>`)const stream = ReactDOMStream.renderToStaticMarkup(<App data={data} />);stream.pipe(res)

13

Page 14: React. Redux. Real world.

Redux14

Page 15: React. Redux. Real world.

DevTools, Logger,

Time travelling15

Page 16: React. Redux. Real world.

Простота16

Page 17: React. Redux. Real world.

Redux

const reducer = (oldState = `FOO`, action) => { switch(action.type) { case `UPDATE_FOO`: return `BAR` } return oldState}

const store = createStore(reducer)

17

// подписаться на обновления

store.subscribe(() => { assert.ok(store.getState() === `BAR`)})

// передать измененияstore.dispatch({ type: `UPDATE_FOO`})

// получить текущее состояниеassert.ok(store.getState() === `FOO`)

Page 18: React. Redux. Real world.

Tests

const reducer = (oldState, action) => { switch(action.type) { case `ACTION_TYPE`: return action.payload }}

assert.ok(reducer(``, `BAR`) === `BAR`)

18

Page 19: React. Redux. Real world.

React + Redux

<Provider store={store}> <ButtonContainer /></Provider>

const Button = ({handleClick, title}) => ( <button onClick={handleClick}>{title}</button>)

19

const mapStateToProps = state => ({ title: state.title})

const mapDispatchToProps = dispatch => ({ handleClick: () => dispatch({ type: `CLICK` })})

const ButtonContainer = connect(mapStateToProps, mapDispatchToProps)(Button)

Page 20: React. Redux. Real world.

Immutable20

Page 21: React. Redux. Real world.

spread...

const initialState = { foo: `foo`, bar: `bar`}const reducer = (state = initialState, action) => { switch(action.type) { case `UPDATE_BAR`: return { ...state, bar: `baz` } }}

return { ...state, we: { ...state.we, must: { ...state.we.must, go: { ...state.we.must.go, deeper: action.payload } } }}

21

Page 22: React. Redux. Real world.

Immutable.js

return { ...state, we: { ...state.we, must: { ...state.we.must, go: { ...state.we.must.go, deeper: action.payload } } }}

return state.setIn([`we`, `must`, `go`, `deeper`], action.payload)

22

Page 23: React. Redux. Real world.

Immutable.js

const mapStateToProps = state => ({ foo: state.get(`foo`), bar: state.get(`bar`), ...})

import { Map } from 'immutable'

const map = Map({ foo: `bar`})

const { foo } = map

assert.fails(foo === `bar`)assert.ok(foo === undefined)

23

Page 24: React. Redux. Real world.

Seamless-immutable

import Immutable from 'seamless-immutable'

const map = Immutable({foo: `bar`})

const { foo } = map

assert.ok(foo === `bar`)

24

Object.freeze()~5 KB

return state.setIn([`we`, `must`, `go`, `deeper`], action.payload)

Page 25: React. Redux. Real world.

Расчеты25

Page 26: React. Redux. Real world.

26

Page 27: React. Redux. Real world.

Вычисления

const computeAction = data => { const result = compute(data)

return { type: `COMPUTE_ACTION`, payload: result }}

27

Page 28: React. Redux. Real world.

Масштабирование

28

state

<Component1 ... />

<Component2 ... />

<Component3 ... />

<Component4 ... />

compute1

compute2

compute3

compute4

Page 29: React. Redux. Real world.

Вычисления

29

const mapStateToProps = state => ({ result: compute(state.data)})

Page 30: React. Redux. Real world.

Мемоизация | Reselect

import { createSelector } from 'reselect'

const clustersSelector = createSelector( state => state.points, state => state.map.zoom, (points, zoom) => calculateClusters(points, zoom))

30

Page 31: React. Redux. Real world.

Actions31

Page 32: React. Redux. Real world.

Flux Standard Action

{ type: `DO_SOMETHING`, payload: { foo: `bar` },

meta: { foo: `bar` }}

32

{ type: `DO_SOMETHING`, payload: new Error(), error: true}

Page 33: React. Redux. Real world.

Realtime

REALTIME gif

Синхронизация экранов

33

Page 34: React. Redux. Real world.

Plain object

34

store.dispatch(...)

store.dispatch(...)

store.dispatch(...)

store.dispatch(...)

SOCKETS

if(action.meta && action.meta.sync) { sockets.emit(action)}

Page 35: React. Redux. Real world.

thunk

const asyncAction = () => dispatch => { dispatch({ type: `REQUEST` }) fetch() .then(() => dispatch({type: `REQUEST_SUCCESS`})) .catch(() => dispatch({type: `REQUEST_ERROR`}))}

35

Page 36: React. Redux. Real world.

thunk??export const finallySend = () => (dispatch, getState) => { const {phone, location, latlng, description, uploadId} = getState().toJS() dispatch({ type: SEND_REQUEST }) if (isEmpty(latlng)) { if (!location) { dispatch(sendResults({phone, location, description, uploadId})) return dispatch(setStep(`done`)) } geocodeLocation(location).then(payload => { const {lat: photoLat, lng: photoLon} = payload dispatch(sendResults({phone, location, description, uploadId, photoLat, photoLon})) }) } else { const {lat: photoLat, lng: photoLon} = latlng dispatch(sendResults({phone, location, description, uploadId, photoLat, photoLon})) } dispatch(setStep(`done`))}

36

tests?scale?

Page 37: React. Redux. Real world.

SAGA37

Page 38: React. Redux. Real world.

Sagas

38

ON_CLICK

REQUEST

REQUEST_SUCCESS

function* rootSaga() { yield takeLatest(`CLICK`, request) }

function* request() { try { yield put({type: `REQUEST`}) const payload = yield call(api.requestData) yield put({type: `REQUEST_SUCCESS`, payload}) } catch(e) { yield put({type: `REQUEST_ERROR`}) }}

Page 39: React. Redux. Real world.

Тесты

const generator = request()

expect(generator.next().value).toEqual(put({type: `REQUEST`))expect(generator.next().value).toEqual(call(api.requestData))expect(generator.next(dummyResponse).value).toEqual(put({type: `REQUEST_SUCCESS`, payload}))

39

Page 40: React. Redux. Real world.

Изоляция40

Page 41: React. Redux. Real world.

Проблема?

41

Component

Component

Component

Component

const componentReducer = (state, action) => {

... case `CLICK`:

return state.set(`clicked`, true)

….}

cobmineReducers({ component1: componentReducer, component2: componentReducer ...})

`CLICK`

Page 42: React. Redux. Real world.

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

class ReusableComponent extends Component { constructor() { this.state = {clicked: false} } handleOnClick() { this.setState({ clicked: true }) } render() { return <button onClick={this.handleOnClick} /> }}

42

Page 43: React. Redux. Real world.

43

Page 44: React. Redux. Real world.

redux-state

connectState(

mapLocalStateToProps,

mapLocalDispatchToProps,

mergeProps,

componentReducer

)(Component)

44

import {reducer as states} from `redux-state`

combineReducers({ states, ...})

Page 45: React. Redux. Real world.

redux-multireducer

45

Component

Component

Component

Component

cobmineReducers({ component: multireducer({ `component1`: componentReducer, `component2`: componentReducer, `component3`: componentReducer, ... }), ...})

`CLICK_reducerKey=component1``CLICK_reducerKey=component2``CLICK_reducerKey=component3`

saga?

Page 46: React. Redux. Real world.

ELM architecture

46

Page 47: React. Redux. Real world.

47

ELMModel

UpdateCommand

ViewModularity

REDUXStateReducerSagaComponet???

Page 48: React. Redux. Real world.

48

UpdaterModel

CommandView

Page 49: React. Redux. Real world.

elm

49

Parent

Child

Child

Page 50: React. Redux. Real world.

redux-elm

//parentUpdaterimport { Updater } from 'redux-elm';import childUpdater, { init as childInit } from './childUpdater'export const init = () => Immutable({ child1: childInit(), child2: childInit()});export default new Updater(init(), saga) .case(`Child1`, (model, action) => childUpdater(model.child1, action)) .case(`Child2`, (model, action) => childUpdater(model.child2, action)) .toReducer();

50

Page 51: React. Redux. Real world.

redux-elm

//Parentimport { forwardTo, view } from 'redux-elm'import ChildView from 'redux-elm'

export default view(({ model, dispatch }) => ( <div> <ChildView model={model} dispatch={forwardTo(dispatch, `Child1`)} /> <ChildView model={model} dispatch={forwardTo(dispatch, `Child2`)} /> </div>));

51

Page 52: React. Redux. Real world.

AMAZING REDUX

seamless-immutable/immutable.js

reselect

redux-saga

redux-elm52

Page 53: React. Redux. Real world.

Спасибо за внимание!

53