React frameworks

Занятие 7

Профессия
Node.js & React.js developer
продвинутый курс

1

  • Зачем нужны фреймворки?
  • Flux
  • Redux
  • MobX
  • Relay
  • Summary

План

2

Что такое framework и зачем он нужен?

2

  • Library
  • CMS
  • Framework
  • State manager
const lib = require('some-lib');
lib.show();

/models
/views
/controllers

/components
/containers

The terms

  • Программный код, API
  • Структура проекта и рекомендации
  • Использование сторонних решений

3

Flux

3

Flux

Data flow

3

3

3

3

3

3

3

Example

src
├── containers
│   └── AppContainer.js
├── data
│   ├── TodoActions.js
│   ├── TodoActionTypes.js
│   ├── TodoDispatcher.js
│   └── TodoStore.js
├── root.js
└── views
    └── AppView.js

3

Example

TodoDispatcher.js

import {Dispatcher} from 'flux';

export default new Dispatcher();

3

Example

TodoActionTypes.js

const ActionTypes = {
  ADD_TODO: 'ADD_TODO',
};

export default ActionTypes;

3

Example

TodoActions.js

import TodoActionTypes from './TodoActionTypes';
import TodoDispatcher from './TodoDispatcher';

const Actions = {
  addTodo(text) {
    TodoDispatcher.dispatch({
      type: TodoActionTypes.ADD_TODO,
      text,
    });
  },
};

export default Actions;

3

Example

TodoStore.js

import Immutable from 'immutable';
import {ReduceStore} from 'flux/utils';
import TodoActionTypes from './TodoActionTypes';
import TodoDispatcher from './TodoDispatcher';

class TodoStore extends ReduceStore {
  constructor() {
    super(TodoDispatcher);
  }
  getInitialState() {
    return Immutable.OrderedMap();
  }
  reduce(state, action) {
    switch (action.type) {
      case TodoActionTypes.ADD_TODO:
        // Do nothing for now, we will add logic here soon!
        return state;
      default:
        return state;
    }
  }
}

export default new TodoStore();

3

Example

AppContainer.js

import AppView from '../views/AppView';
import {Container} from 'flux/utils';
import TodoStore from '../data/TodoStore';

function getStores() {
  return [
    TodoStore,
  ];
}

function getState() {
  return {
    todos: TodoStore.getState(),
  };
}

export default Container.createFunctional(AppView, getStores, getState);

3

Summary

3

  • Архитектура
  • Сложность в понимании
  • Предсказуемость
  • Много действий для простого эффекта

4

Redux

4

Redux

4

4

4

Container Components   and

Redux

 

Presentational Components

Provider           and    @connect

4

Example

index.js

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'

let store = createStore(todoApp)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

4

Example

actions/index.js

let nextTodoId = 0
export const addTodo = (text) => {
  return {
    type: 'ADD_TODO',
    id: nextTodoId++,
    text
  }
}

export const setVisibilityFilter = (filter) => {
  return {
    type: 'SET_VISIBILITY_FILTER',
    filter
  }
}

export const toggleTodo = (id) => {
  return {
    type: 'TOGGLE_TODO',
    id
  }
}

4

Example

reducers/todos.js

const todo = (state = {}, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return {
        id: action.id,
        text: action.text,
        completed: false
      }
    case 'TOGGLE_TODO':
      if (state.id !== action.id) {
        return state
      }

      return Object.assign({}, state, {
        completed: !state.completed
      })

    default:
      return state
  }
}
const todos = (state = [], action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        todo(undefined, action)
      ]
    case 'TOGGLE_TODO':
      return state.map(t =>
        todo(t, action)
      )
    default:
      return state
  }
}

export default todos

4

Example

reducers/visibilityFilter.js

const visibilityFilter = (state = 'SHOW_ALL', action) => {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter
    default:
      return state
  }
}

export default visibilityFilter

4

Example

Presentational Components

 

components/Todo.js

components/TodoList.js

components/Link.js

components/Footer.js

 

 

 

 

redux.js.org/docs/basics/ExampleTodoList.html

4

Example

containers/VisibleTodoList.js

import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_ALL': return todos
    case 'SHOW_COMPLETED': return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE': return todos.filter(t => !t.completed)
  }
}

4

Example

containers/VisibleTodoList.js

...

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

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList

4

4

Summary

  • Архитектура
  • Предсказуемость
  • Литература, переводы
  • Путаница в терминах
  • Каждый стартеркит ~= фреймворк
  • Много действий для простого эффекта

5

MobX

MobX

5

MobX

5

MobX

5

MobX

5

<Provider>  &  @inject

Example

import {observable} from 'mobx';

var appState = observable({
    timer: 0
});

5

Example

appState.resetTimer = function reset() {
    appState.timer = 0;
};

setInterval(function tick() {
    appState.timer += 1;
}, 1000);

5

Example

import {observer} from 'mobx-react';

@observer
class TimerView extends React.Component {
    render() {
        return (<button onClick={this.onReset.bind(this)}>
                Seconds passed: {this.props.appState.timer}
            </button>);
    }

    onReset () {
        this.props.appState.resetTimer();
    }
};

React.render(<TimerView appState={appState} />, document.body);

5

Summary

5

  • Нет архитектуры
  • @someMagic

6

Relay

2

Relay

2

GraphQL

2

Relay

2

Relay

2

Example

Example

class Tea extends React.Component {
  render() {
    var {name, steepingTime} = this.props.tea;
    return (
      <li key={name}>
        {name} (<em>{steepingTime} min</em>)
      </li>
    );
  }
}

Tea = Relay.createContainer(Tea, {
  fragments: {
    tea: () => Relay.QL`
      fragment on Tea {
        name,
        steepingTime,
      }
    `,
  },
});

2

Example

class TeaStore extends React.Component {
  render() {
    return <ul>
      {this.props.store.teas.map(
        tea => <Tea tea={tea} />
      )}
    </ul>;
  }
}
TeaStore = Relay.createContainer(TeaStore, {
  fragments: {
    store: () => Relay.QL`
      fragment on Store {
        teas { ${Tea.getFragment('tea')} },
      }
    `,
  },
});

2

Example

class TeaHomeRoute extends Relay.Route {
  static routeName = 'Home';
  static queries = {
    store: (Component) => Relay.QL`
      query TeaStoreQuery {
        store { ${Component.getFragment('store')} },
      }
    `,
  };
}

ReactDOM.render(
  <Relay.RootContainer
    Component={TeaStore}
    route={new TeaHomeRoute()}
  />,
  mountNode
);

2

Summary

2

  • Magic!
  • GraphQL, Relay.QL, Routes
  • client-server subscribes

7

Summary

7

Client-server communication

Restful?

Websockets?

Subscribers?

 

7

Universal

client-server

models?

7

State management

7

7

Provider & injector

7

7

JS - это
не только

REACT

Игорь Суворов

Thanks!

any questions?

программист-предприниматель

Made with Slides.com