Created
December 3, 2019 21:42
-
-
Save raydot/5be8c4cc80209e1bb22bd09f41585764 to your computer and use it in GitHub Desktop.
Redux Tutorial Video 22 -- Extracting Container Components // source https://jsbin.com/neseqom
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta name="description" content="Video 22 -- Extracting Container Components"> | |
<meta charset="utf-8"> | |
<title>Redux Tutorial</title> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.4/redux.min.js"></script> | |
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> | |
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> | |
</head> | |
<body> | |
<div id='root'></div> | |
<script id="jsbin-javascript"> | |
// So the downside of putting all of the reducers into the container is that we have to pass a lot of props around. Let's see if we can't do better! | |
// Notice, for instance, visibilityFilter => currentFilter, all over the place. Parents need to know to much about what children need so it breaks encapsulation. | |
'use strict'; | |
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); | |
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; | |
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | |
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } | |
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | |
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | |
var todo = function 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 _extends({}, state, { | |
completed: !state.completed | |
}); | |
default: | |
return state; | |
} | |
}; | |
// todos reducer | |
var todos = function todos(state, action) { | |
if (state === undefined) state = []; | |
switch (action.type) { | |
case 'ADD_TODO': | |
return [].concat(_toConsumableArray(state), [// return array with all items + new | |
todo(undefined, action) // calls child reducers | |
]); | |
case 'TOGGLE_TODO': | |
return state.map(function (t) { | |
return todo(t, action); | |
}); | |
default: | |
return state; | |
} | |
}; | |
var visibilityFilter = function visibilityFilter(state, action) { | |
if (state === undefined) state = 'SHOW_ALL'; | |
switch (action.type) { | |
case 'SET_VISIBILITY_FILTER': | |
return action.filter; | |
default: | |
return state; | |
} | |
}; | |
var _Redux = Redux; | |
var combineReducers = _Redux.combineReducers; | |
// This is the root reducer | |
var todoApp = combineReducers({ | |
todos: todos, | |
visibilityFilter: visibilityFilter | |
}); | |
var _Redux2 = Redux; | |
var createStore = _Redux2.createStore; | |
// combined reducer | |
var store = createStore(todoApp); | |
var _React = React; | |
var Component = _React.Component; | |
// react presentational component for utilizing visibility filter | |
var Link = function Link(_ref) { | |
var active = _ref.active; | |
var children = _ref.children; | |
var onClick = _ref.onClick; | |
if (active) { | |
return React.createElement( | |
'span', | |
null, | |
children | |
); | |
} | |
return React.createElement( | |
'a', | |
{ href: '#', | |
onClick: function (e) { | |
e.preventDefault(); | |
onClick(); | |
} | |
}, | |
children | |
); | |
}; | |
// container to provide data and behavior to presentational component | |
var FilterLink = (function (_Component) { | |
_inherits(FilterLink, _Component); | |
function FilterLink() { | |
_classCallCheck(this, FilterLink); | |
_get(Object.getPrototypeOf(FilterLink.prototype), 'constructor', this).apply(this, arguments); | |
} | |
// Container component | |
_createClass(FilterLink, [{ | |
key: 'componentDidMount', | |
value: function componentDidMount() { | |
var _this = this; | |
// Unsubscribe() is returned by subscribe() | |
this.unsubscribe = store.subscribe(function () { | |
return _this.forceUpdate(); | |
}); | |
} | |
}, { | |
key: 'componentWillUnmount', | |
value: function componentWillUnmount() { | |
this.unsubscribe(); | |
} | |
}, { | |
key: 'render', | |
value: function render() { | |
var props = this.props; | |
var state = store.getState(); | |
// delegate rendering to presentational component. | |
return React.createElement( | |
Link, | |
{ | |
active: props.filter === state.visibilityFilter, | |
onClick: function () { | |
return store.dispatch({ | |
type: 'SET_VISIBILITY_FILTER', | |
filter: props.filter | |
}); | |
} | |
}, | |
props.children | |
); //return | |
} | |
}]); | |
return FilterLink; | |
})(Component); | |
var Footer = function Footer() { | |
return React.createElement( | |
'p', | |
null, | |
'Show:', | |
' ', | |
React.createElement( | |
FilterLink, | |
{ | |
filter: 'SHOW_ALL' | |
}, | |
'All' | |
), | |
', ', | |
React.createElement( | |
FilterLink, | |
{ | |
filter: 'SHOW_ACTIVE' | |
}, | |
'Active' | |
), | |
', ', | |
React.createElement( | |
FilterLink, | |
{ | |
filter: 'SHOW_COMPLETED' | |
}, | |
'Completed' | |
) | |
); | |
}; | |
// Purely presentational Todo component | |
var Todo = function Todo(_ref2) { | |
var onClick = _ref2.onClick; | |
var completed = _ref2.completed; | |
var text = _ref2.text; | |
var id = _ref2.id; | |
return React.createElement( | |
'li', | |
{ | |
onClick: onClick, | |
style: { | |
textDecoration: completed ? 'line-through' : 'none' | |
} | |
}, | |
id, | |
': ', | |
text | |
); | |
}; | |
// Purely presentational TodoList | |
var TodoList = function TodoList(_ref3) { | |
var todos = _ref3.todos; | |
var onTodoClick = _ref3.onTodoClick; | |
return React.createElement( | |
'ul', | |
null, | |
todos.map(function (todo) { | |
return React.createElement(Todo, _extends({ | |
key: todo.id | |
}, todo, { | |
onClick: function () { | |
return onTodoClick(todo.id); | |
} | |
})); | |
}) | |
); | |
}; | |
// Purely presentational AddTodo | |
var AddTodo = function AddTodo(_ref4) { | |
var onAddClick = _ref4.onAddClick; | |
var input = undefined; | |
return React.createElement( | |
'div', | |
null, | |
React.createElement('input', { ref: function (node) { | |
input = node; | |
} }), | |
React.createElement( | |
'button', | |
{ onClick: function () { | |
onAddClick(input.value); | |
input.value = ''; | |
} }, | |
'Add Todo' | |
) | |
); | |
}; | |
var getVisibleTodos = function getVisibleTodos(todos, filter) { | |
switch (filter) { | |
case 'SHOW_ALL': | |
return todos; | |
case 'SHOW_COMPLETED': | |
return todos.filter(function (t) { | |
return t.completed; | |
}); | |
case 'SHOW_ACTIVE': | |
return todos.filter(function (t) { | |
return !t.completed; | |
}); | |
} | |
}; | |
var nextTodoId = 0; | |
// With the refactor of TodoList, AddTodo, and Footer, TodoApp() this is now acting as a container component. | |
var TodoApp = function TodoApp(_ref5) { | |
var todos = _ref5.todos; | |
var visibilityFilter = _ref5.visibilityFilter; | |
return React.createElement( | |
'div', | |
null, | |
React.createElement(AddTodo, { | |
onAddClick: function (text) { | |
return store.dispatch({ | |
type: 'ADD_TODO', | |
id: nextTodoId++, | |
text: text | |
}); | |
} | |
}), | |
React.createElement(TodoList, { | |
todos: getVisibleTodos(todos, visibilityFilter), | |
onTodoClick: function (id) { | |
return store.dispatch({ | |
type: 'TOGGLE_TODO', | |
id: id | |
}); | |
} | |
}), | |
React.createElement(Footer, null) | |
); | |
}; | |
var render = function render() { | |
ReactDOM.render( | |
// passes to component as prop, every state filled in inside the state object. | |
React.createElement(TodoApp, store.getState()), document.getElementById('root')); | |
}; | |
store.subscribe(render); // runs on any state change | |
render(); | |
</script> | |
<script id="jsbin-source-javascript" type="text/javascript">// So the downside of putting all of the reducers into the container is that we have to pass a lot of props around. Let's see if we can't do better! | |
// Notice, for instance, visibilityFilter => currentFilter, all over the place. Parents need to know to much about what children need so it breaks encapsulation. | |
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 { | |
...state, | |
completed: !state.completed | |
} | |
default: | |
return state | |
} | |
} | |
// todos reducer | |
const todos = (state = [], action) => { | |
switch (action.type) { | |
case 'ADD_TODO': | |
return [ | |
...state, // return array with all items + new | |
todo(undefined, action) // calls child reducers | |
] | |
case 'TOGGLE_TODO': | |
return state.map(t => todo(t, action)) | |
default: | |
return state; | |
} | |
}; | |
const visibilityFilter = ( | |
state = 'SHOW_ALL', | |
action | |
) => { | |
switch (action.type) { | |
case 'SET_VISIBILITY_FILTER': | |
return action.filter; | |
default: | |
return state; | |
} | |
} | |
const { combineReducers } = Redux | |
// This is the root reducer | |
const todoApp = combineReducers({ | |
todos, | |
visibilityFilter | |
}) | |
const { createStore } = Redux | |
// combined reducer | |
const store = createStore(todoApp) | |
const { Component } = React | |
// react presentational component for utilizing visibility filter | |
const Link = ({ | |
active, | |
children, | |
onClick | |
}) => { | |
if (active) { | |
return <span>{children}</span>; | |
} | |
return ( | |
<a href='#' | |
onClick={e => { | |
e.preventDefault(); | |
onClick() | |
}} | |
> | |
{children} | |
</a> | |
); | |
}; | |
// container to provide data and behavior to presentational component | |
class FilterLink extends Component { | |
componentDidMount() { | |
// Unsubscribe() is returned by subscribe() | |
this.unsubscribe = store.subscribe(() => | |
this.forceUpdate() | |
); | |
} | |
componentWillUnmount() { | |
this.unsubscribe(); | |
} | |
render() { | |
const props = this.props; | |
const state = store.getState(); | |
// delegate rendering to presentational component. | |
return ( | |
<Link | |
active={ | |
props.filter === | |
state.visibilityFilter | |
} | |
onClick = {() => | |
store.dispatch({ | |
type: 'SET_VISIBILITY_FILTER', | |
filter: props.filter | |
}) | |
} | |
> | |
{props.children} | |
</Link> | |
); //return | |
} | |
} | |
// Container component | |
const Footer = () => ( | |
<p> | |
Show: | |
{' '} | |
<FilterLink | |
filter='SHOW_ALL' | |
> | |
All | |
</FilterLink> | |
{', '} | |
<FilterLink | |
filter='SHOW_ACTIVE' | |
> | |
Active | |
</FilterLink> | |
{', '} | |
<FilterLink | |
filter='SHOW_COMPLETED' | |
> | |
Completed | |
</FilterLink> | |
</p> | |
); | |
// Purely presentational Todo component | |
const Todo = ({ | |
onClick, | |
completed, | |
text, | |
id | |
}) => ( | |
<li | |
onClick={onClick} | |
style={{ | |
textDecoration: | |
completed ? | |
'line-through' : | |
'none' | |
}} | |
> | |
{id}: {text} | |
</li> | |
); | |
// Purely presentational TodoList | |
const TodoList = ({ | |
todos, | |
onTodoClick | |
}) => ( | |
<ul> | |
{todos.map(todo => | |
<Todo | |
key={todo.id} | |
{...todo} | |
onClick={() => onTodoClick(todo.id)} | |
/> | |
)} | |
</ul> | |
); | |
// Purely presentational AddTodo | |
const AddTodo = ({ | |
onAddClick | |
}) => { | |
let input; | |
return ( | |
<div> | |
<input ref={node => { | |
input = node; | |
}} /> | |
<button onClick = {() => { | |
onAddClick(input.value); | |
input.value=''; | |
}}> | |
Add Todo | |
</button> | |
</div> | |
); | |
}; | |
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 | |
); | |
} | |
} | |
let nextTodoId = 0; | |
// With the refactor of TodoList, AddTodo, and Footer, TodoApp() this is now acting as a container component. | |
const TodoApp =({ | |
todos, | |
visibilityFilter | |
}) => ( | |
<div> | |
<AddTodo | |
onAddClick={text => | |
store.dispatch({ | |
type: 'ADD_TODO', | |
id: nextTodoId++, | |
text | |
}) | |
} | |
/> | |
<TodoList | |
todos = { | |
getVisibleTodos( | |
todos, | |
visibilityFilter | |
) | |
} | |
onTodoClick = {id => | |
store.dispatch({ | |
type: 'TOGGLE_TODO', | |
id | |
}) | |
} | |
/> | |
<Footer /> | |
</div> | |
); | |
const render = () => { | |
ReactDOM.render( | |
// passes to component as prop, every state filled in inside the state object. | |
<TodoApp | |
{...store.getState()} | |
/>, | |
document.getElementById('root') | |
) | |
} | |
store.subscribe(render) // runs on any state change | |
render()</script></body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// So the downside of putting all of the reducers into the container is that we have to pass a lot of props around. Let's see if we can't do better! | |
// Notice, for instance, visibilityFilter => currentFilter, all over the place. Parents need to know to much about what children need so it breaks encapsulation. | |
'use strict'; | |
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); | |
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; | |
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | |
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } | |
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | |
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | |
var todo = function 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 _extends({}, state, { | |
completed: !state.completed | |
}); | |
default: | |
return state; | |
} | |
}; | |
// todos reducer | |
var todos = function todos(state, action) { | |
if (state === undefined) state = []; | |
switch (action.type) { | |
case 'ADD_TODO': | |
return [].concat(_toConsumableArray(state), [// return array with all items + new | |
todo(undefined, action) // calls child reducers | |
]); | |
case 'TOGGLE_TODO': | |
return state.map(function (t) { | |
return todo(t, action); | |
}); | |
default: | |
return state; | |
} | |
}; | |
var visibilityFilter = function visibilityFilter(state, action) { | |
if (state === undefined) state = 'SHOW_ALL'; | |
switch (action.type) { | |
case 'SET_VISIBILITY_FILTER': | |
return action.filter; | |
default: | |
return state; | |
} | |
}; | |
var _Redux = Redux; | |
var combineReducers = _Redux.combineReducers; | |
// This is the root reducer | |
var todoApp = combineReducers({ | |
todos: todos, | |
visibilityFilter: visibilityFilter | |
}); | |
var _Redux2 = Redux; | |
var createStore = _Redux2.createStore; | |
// combined reducer | |
var store = createStore(todoApp); | |
var _React = React; | |
var Component = _React.Component; | |
// react presentational component for utilizing visibility filter | |
var Link = function Link(_ref) { | |
var active = _ref.active; | |
var children = _ref.children; | |
var onClick = _ref.onClick; | |
if (active) { | |
return React.createElement( | |
'span', | |
null, | |
children | |
); | |
} | |
return React.createElement( | |
'a', | |
{ href: '#', | |
onClick: function (e) { | |
e.preventDefault(); | |
onClick(); | |
} | |
}, | |
children | |
); | |
}; | |
// container to provide data and behavior to presentational component | |
var FilterLink = (function (_Component) { | |
_inherits(FilterLink, _Component); | |
function FilterLink() { | |
_classCallCheck(this, FilterLink); | |
_get(Object.getPrototypeOf(FilterLink.prototype), 'constructor', this).apply(this, arguments); | |
} | |
// Container component | |
_createClass(FilterLink, [{ | |
key: 'componentDidMount', | |
value: function componentDidMount() { | |
var _this = this; | |
// Unsubscribe() is returned by subscribe() | |
this.unsubscribe = store.subscribe(function () { | |
return _this.forceUpdate(); | |
}); | |
} | |
}, { | |
key: 'componentWillUnmount', | |
value: function componentWillUnmount() { | |
this.unsubscribe(); | |
} | |
}, { | |
key: 'render', | |
value: function render() { | |
var props = this.props; | |
var state = store.getState(); | |
// delegate rendering to presentational component. | |
return React.createElement( | |
Link, | |
{ | |
active: props.filter === state.visibilityFilter, | |
onClick: function () { | |
return store.dispatch({ | |
type: 'SET_VISIBILITY_FILTER', | |
filter: props.filter | |
}); | |
} | |
}, | |
props.children | |
); //return | |
} | |
}]); | |
return FilterLink; | |
})(Component); | |
var Footer = function Footer() { | |
return React.createElement( | |
'p', | |
null, | |
'Show:', | |
' ', | |
React.createElement( | |
FilterLink, | |
{ | |
filter: 'SHOW_ALL' | |
}, | |
'All' | |
), | |
', ', | |
React.createElement( | |
FilterLink, | |
{ | |
filter: 'SHOW_ACTIVE' | |
}, | |
'Active' | |
), | |
', ', | |
React.createElement( | |
FilterLink, | |
{ | |
filter: 'SHOW_COMPLETED' | |
}, | |
'Completed' | |
) | |
); | |
}; | |
// Purely presentational Todo component | |
var Todo = function Todo(_ref2) { | |
var onClick = _ref2.onClick; | |
var completed = _ref2.completed; | |
var text = _ref2.text; | |
var id = _ref2.id; | |
return React.createElement( | |
'li', | |
{ | |
onClick: onClick, | |
style: { | |
textDecoration: completed ? 'line-through' : 'none' | |
} | |
}, | |
id, | |
': ', | |
text | |
); | |
}; | |
// Purely presentational TodoList | |
var TodoList = function TodoList(_ref3) { | |
var todos = _ref3.todos; | |
var onTodoClick = _ref3.onTodoClick; | |
return React.createElement( | |
'ul', | |
null, | |
todos.map(function (todo) { | |
return React.createElement(Todo, _extends({ | |
key: todo.id | |
}, todo, { | |
onClick: function () { | |
return onTodoClick(todo.id); | |
} | |
})); | |
}) | |
); | |
}; | |
// Purely presentational AddTodo | |
var AddTodo = function AddTodo(_ref4) { | |
var onAddClick = _ref4.onAddClick; | |
var input = undefined; | |
return React.createElement( | |
'div', | |
null, | |
React.createElement('input', { ref: function (node) { | |
input = node; | |
} }), | |
React.createElement( | |
'button', | |
{ onClick: function () { | |
onAddClick(input.value); | |
input.value = ''; | |
} }, | |
'Add Todo' | |
) | |
); | |
}; | |
var getVisibleTodos = function getVisibleTodos(todos, filter) { | |
switch (filter) { | |
case 'SHOW_ALL': | |
return todos; | |
case 'SHOW_COMPLETED': | |
return todos.filter(function (t) { | |
return t.completed; | |
}); | |
case 'SHOW_ACTIVE': | |
return todos.filter(function (t) { | |
return !t.completed; | |
}); | |
} | |
}; | |
var nextTodoId = 0; | |
// With the refactor of TodoList, AddTodo, and Footer, TodoApp() this is now acting as a container component. | |
var TodoApp = function TodoApp(_ref5) { | |
var todos = _ref5.todos; | |
var visibilityFilter = _ref5.visibilityFilter; | |
return React.createElement( | |
'div', | |
null, | |
React.createElement(AddTodo, { | |
onAddClick: function (text) { | |
return store.dispatch({ | |
type: 'ADD_TODO', | |
id: nextTodoId++, | |
text: text | |
}); | |
} | |
}), | |
React.createElement(TodoList, { | |
todos: getVisibleTodos(todos, visibilityFilter), | |
onTodoClick: function (id) { | |
return store.dispatch({ | |
type: 'TOGGLE_TODO', | |
id: id | |
}); | |
} | |
}), | |
React.createElement(Footer, null) | |
); | |
}; | |
var render = function render() { | |
ReactDOM.render( | |
// passes to component as prop, every state filled in inside the state object. | |
React.createElement(TodoApp, store.getState()), document.getElementById('root')); | |
}; | |
store.subscribe(render); // runs on any state change | |
render(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment