KEMBAR78
React и redux | PPTX
Dmitry Radyno
React и Redux
Templates
Templates
Место
для
чистосердечного признания
Templates
+ Похоже на HTML
+ Зависимость от состояния
Templates
var state = {
email: "dmitry.radyno@gmail.com",
rememberMe: true,
warnings: []
}
render(state);
Templates
var render = function(state) {
var source = "<input type='text' value='{{email}}'> ...",
template = Handlebars.compile(source),
html = template(state);
document.getElementById("root").innerHTML = html;
};
Templates
Flickering
Templates
+ Похоже на HTML
+ Зависимость от состояния
- Мигание
* Плохая подсветка синтаксиса
* Неудобная отладка
“A JAVASCRIPT
LIBRARY FOR
BUILDING USER
INTERFACES”
React Components
var HelloWorld = React.createClass({
render: function() {
return <div>
Hello,
<span className="bold">{this.props.name}</span>!
</div>;
}
});
ReactDOM.render(<HelloWorld name="World" />, root);
Похож на HTML
class => className
for => htmlFor
{js code goes here}
Зависимость от состояния
render(state);
События
onClick, onChange, onHover,
onBlur, onBlablabla, …
render() {
return (
<div className="search-input">
<input type="text" onChange={this.onChangeHandler} />
<button onClick={this.onClickHandler}>Искать</button>
</div>
);
}
Мигания
Virtual
DOM
React Components
var HelloWorld = React.createClass({
displayName: "HelloWorld",
render: function render() {
return React.createElement("div", null,
"Hello, ",
React.createElement("span", { className: "bold" },
this.props.name),
"!“
);
}
});
ReactDOM.render(React.createElement(HelloWorld, { name: "World" }), root);
React Summary
+ Похоже на HTML
+ Зависимость от состояния
+ Мигание
+ Работа с событиями
* Плохая подсветка синтаксиса
* Неудобная отладка
Redux
“is a predictable state container for
JavaScript apps”
Redux
“лучший способ понять Redux –
реализовать его самому”
Redux
var state = {
tasks: ["To learn React", "To read book"],
sortBy: "name“
};
Redux
var render = function(state) {
var root = document.getElementById("root");
var html = "<ul>Amount of tasks: " + state.tasks.length;
html += state.tasks.map(function(task) {
return "<li>" + task + "</li>";
}).join("");
html += "</ul>";
html += "<input type='text' id='taskInput' value='' />";
html += "<button id='addTask'>Add</button>";
root.innerHTML = html;
document.getElementById("addTask").addEventListener("click", function() {
var task = document.getElementById("taskInput").value;
console.log("I want to add task: " + task);
}, false);
};
Redux
var state = {
tasks: ["To learn React", "To read book"],
sortBy: "name“
};
var render = function(state) { … };
render(state);
Redux
Single source of truth
Redux
State is read-only
Redux
var createStore = function(initialState) {
var state = initialState;
var getState = function() {
return state;
};
return {
getState: getState
};
};
Redux
var createStore = function(initialState) { … };
var store = createStore({
tasks: ["To learn React", "To read book"],
sortBy: "name“
});
var render = function(state) { ... };
render(store.getState());
Redux - subscriptions
var createStore = function(initialState) {
…
var subscriptions = [];
var subscribe = function(subscription) {
subscriptions.push(subscription);
};
return {
getState: getState,
subscribe: subscribe
};
};
Redux - subscriptions
var createStore = function(initialState) {
…
var stateChanged = function() {
subscriptions.forEach(function(subscription) {
subscription();
});
};
return {
getState: getState,
subscribe: subscribe
};
};
Redux - subscribing
…
render(store.getState());
store.subscribe(function() {
render(store.getState());
});
Redux
var createStore = function(initialState) {
var state = initialState;
var getState = function() { … };
var subscriptions = [];
var subscribe = function(subscription) { … };
var stateChanged = function() { … };
return {
getState: getState,
subscribe: subscribe
};
};
Redux
var createStore = function(initialState) { … };
var store = createStore({
tasks: ["To learn React", "To read book"],
sortBy: "name“
});
var render = function(state) { ... };
render(store.getState());
store.subscribe(function() {
render(store.getState());
});
Redux – changes
Смешная картинка об
изменениях здесь
Redux – actions
{
type: "ADD_TASK",
data: taskName
}
Redux – actions
var addTask = function(taskName) {
return {
type: "ADD_TASK",
data: taskName
};
};
addTask(“To write app”);
Redux – actions
store.dispatch(addTask("To write app"));
Redux – dispatch
var createStore = function(initialState) {
...
var dispatch = function(action) { … };
return {
getState: getState,
subscribe: subscribe,
dispatch: dispatch
};
};
Redux – reducer
var reducer = function(state, action) {
// …
return state;
};
var dispatch = function(action) {
state = reducer(state, action);
stateChanged();
};
Redux – reducer
var reducer = function(state, action) {
switch (action.type) {
case "ADD_TASK":
return Object.assign({}, state, {
tasks: state.tasks.concat([ action.data ])
});
case "REMOVE_TASK":
var newState = ...;
return newState;
}
return state;
};
Redux – reducer
…
case "ADD_TASK":
return Object.assign({}, state, {
tasks: state.tasks.concat([ action.data ])
});
…
Pure function
Одинаковое значение
для одинакового аргумента
Отсутсвуют сторонние эффекты
(ajax, cookies, database queries)
Redux – dispatch
var createStore = function(initialState) {
var state = initialState;
var getState = function() { … };
var subscriptions = [];
var subscribe = function(subscription) { … };
var stateChanged = function() { … };
var reducer = function(state, action) { … };
var dispatch = function(action) { … };
return {
getState: getState,
subscribe: subscribe,
dispatch: dispatch
};
};
Redux – actions
…
render(store.getState());
store.subscribe(function() {
render(store.getState());
});
store.dispatch(addTask("To write app"));
Redux – Step 1
var addTask = function(taskName) {
return {
type: "ADD_TASK",
data: taskName
};
};
Redux – Step 2
var dispatch = function(action) {
state = reducer(state, action);
stateChanged();
};
Redux – Step 3
var reducer = function(state, action) {
switch (action.type) {
case "ADD_TASK":
return Object.assign({}, state, {
tasks: state.tasks.concat([ action.data ])
});
…
}
return state;
};
Redux – Step 4
var dispatch = function(action) {
state = reducer(state, action);
stateChanged();
};
Redux – Step 5
store.subscribe(function() {
render(store.getState());
});
Redux
Redux – Store
var createStore = function(initialState) {
var state = initialState;
var getState = function() { … };
var subscriptions = [];
var subscribe = function(subscription) { … };
var stateChanged = function() { … };
var reducer = function(state, action) { … };
var dispatch = function(action) { … };
return {
getState: getState,
subscribe: subscribe,
dispatch: dispatch
};
};
Redux – reducers
var createStore = function(reducer, initialState) {
var state = initialState;
var getState = function() { … };
var subscriptions = [];
var subscribe = function(subscription) { … };
var stateChanged = function() { … };
var dispatch = function(action) { … };
return {
getState: getState,
subscribe: subscribe,
dispatch: dispatch
};
};
Redux – reducers
var reducer = function(state, action) {
…
return state;
};
var initialValue = {
tasks: ["To learn React", "To read book"],
sortBy: "name"
};
var store = createStore(reducer, initialValue);
Redux
var createStore = function(reducer, initialState) {
…
return {
getState: getState,
subscribe: subscribe,
dispatch: dispatch
};
};
Где же React?
render(state)
Где же React?
react-redux
React-redux
<Provider store={store}>
<MyIndexPage />
</Provider>
connect(…)
Выгода
Модульность
Слабая связность кода
=>
Тестируемость кода
Инструментарий
Undo/redo
Time travelling
Hot reloading
Render everywhere
DOM
Side-effects
React vs ReactDOM
var HelloWorld = React.createClass({
displayName: "HelloWorld",
render: function render() {
return React.createElement("div", null,
"Hello, ",
React.createElement("span", { className: "bold" },
this.props.name),
"!“
);
}
});
ReactDOM.render(React.createElement(HelloWorld, { name: "World" }), root);
Render everywhere
React – описание UI
ReactDOM – работа с DOM
Render everywhere
import ReactDOMServer from “ReactDom/server”;
…
var html = ReactDOMServer.renderToString(<HelloWorld />);
Достоинства
Тестируемость
Инструментарий
Server-side rendering
В чем подвох?
Сложность сборки
Непривычность
Сборка - Webpack
Webpack
import React from ‘react’;
var MyIndexPage = require(‘components/MyIndexPage.js’);
…
…
JSX, ES2015 - Babel
Webpack + Babel
webpack.config.js
var webpack = require("webpack");
var path = require("path");
module.exports = {
entry: path.resolve(__dirname, "src") + "/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js“
},
module: {
loaders: [{
test: /.jsx?/,
include: path.resolve(__dirname, "src"),
exclude: /node_modules/,
loader: 'babel',
query: { presets: ["es2015", "react"] }
}]
},
resolve: { extensions: ['', '.js', '.jsx'] }
};
Что дальше?
https://facebook.github.io/react/docs/getting-started.html
http://redux.js.org/index.html
https://medium.com/@dan_abramov/the-evolution-of-flux-
frameworks-6c16ad26bb31#.dakcpy2ow
https://medium.com/@dan_abramov/smart-and-dumb-
components-7ca2f9a7c7d0#.32n9x0k4u
https://github.com/rackt/react-redux
Спасибо за внимание
Дмитрий Радыно:
Twitter: @radyno
Facebook: dmitry.radyno
Email: dmitry.radyno@gmail.com
http://blackmarker.by

React и redux