├── .gitignore
├── 01-react-redux-the-single-immutable-state-tree
├── app.css
├── index.html
└── script.jsx
├── 02-react-redux-describing-state-changes-with-actions
├── app.css
├── index.html
└── script.jsx
├── 03-react-redux-pure-and-impure-functions
├── app.css
├── index.html
└── script.jsx
├── 04-javascript-redux-the-reducer-function
├── app.css
├── index.html
└── script.jsx
├── 05-react-redux-writing-a-counter-reducer-with-tests
├── app.css
├── index.html
└── script.jsx
├── 06-react-redux-store-methods-getstate-dispatch-and-subscribe
├── app.css
├── index.html
└── script.jsx
├── 07-react-redux-implementing-store-from-scratch
├── app.css
├── index.html
└── script.jsx
├── 08-react-redux-react-counter-example
├── app.css
├── index.html
└── script.jsx
├── 09-react-redux-avoiding-array-mutations-with-concat-slice-and-spread
├── app.css
├── index.html
└── script.jsx
├── 10-react-redux-avoiding-object-mutations-with-object-assign-and-spread
├── app.css
├── index.html
└── script.jsx
├── 11-react-redux-writing-a-todo-list-reducer-adding-a-todo
├── app.css
├── index.html
└── script.jsx
├── 12-react-redux-writing-a-todo-list-reducer-toggling-a-todo
├── app.css
├── index.html
└── script.jsx
├── 13-react-redux-reducer-composition-with-arrays
├── app.css
├── index.html
└── script.jsx
├── 14-react-redux-reducer-composition-with-objects
├── app.css
├── index.html
└── script.jsx
├── 15-react-redux-reducer-composition-with-combinereducers
├── app.css
├── index.html
└── script.jsx
├── 16-javascript-redux-implementing-combinereducers-from-scratch
├── app.css
├── index.html
└── script.jsx
├── 17-react-redux-react-todo-list-example-adding-a-todo
├── app.css
├── index.html
└── script.jsx
├── 18-react-redux-react-todo-list-example-toggling-a-todo
├── app.css
├── index.html
└── script.jsx
├── 19-react-redux-react-todo-list-example-filtering-todos
├── app.css
├── index.html
└── script.jsx
├── 20-react-redux-extracting-presentational-components-todo-todolist
├── app.css
├── index.html
└── script.jsx
├── 21-react-redux-extracting-presentational-components-addtodo-footer-filterlink
├── app.css
├── index.html
└── script.jsx
├── 22-react-redux-extracting-container-components-filterlink
├── app.css
├── index.html
└── script.jsx
├── 23-react-redux-extracting-container-components-visibletodolist-addtodo
├── app.css
├── index.html
└── script.jsx
├── 24-react-redux-passing-the-store-down-explicitly-via-props
├── app.css
├── index.html
└── script.jsx
├── 25-react-redux-passing-the-store-down-implicitly-via-context
├── app.css
├── index.html
└── script.jsx
├── 26-react-redux-passing-the-store-down-with-provider-from-react-redux
├── app.css
├── index.html
└── script.jsx
├── 27-react-redux-generating-containers-with-connect-from-react-redux-visibletodolist
├── app.css
├── index.html
└── script.jsx
├── 28-react-redux-generating-containers-with-connect-from-react-redux-addtodo
├── app.css
├── index.html
└── script.jsx
├── 29-react-redux-generating-containers-with-connect-from-react-redux-footerlink
├── app.css
├── index.html
└── script.jsx
├── 30-react-redux-extracting-action-creators
├── app.css
├── index.html
└── script.jsx
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/01-react-redux-the-single-immutable-state-tree/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/01-react-redux-the-single-immutable-state-tree/app.css
--------------------------------------------------------------------------------
/01-react-redux-the-single-immutable-state-tree/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/01-react-redux-the-single-immutable-state-tree/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * We will be explaining the code below
3 | * in the following lessons. For now,
4 | * feel free to click around and notice
5 | * how the current state tree is logged
6 | * to the console on every change.
7 | */
8 |
9 | const ADD_TODO = 'ADD_TODO';
10 | const TOGGLE_TODO = 'TOGGLE_TODO';
11 | const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';
12 |
13 | const Filters = {
14 | SHOW_ALL: 'SHOW_ALL',
15 | SHOW_COMPLETED: 'SHOW_COMPLETED',
16 | SHOW_ACTIVE: 'SHOW_ACTIVE'
17 | };
18 |
19 | /*
20 | * Components
21 | */
22 |
23 | class AddTodo extends React.Component {
24 | render() {
25 | return (
26 |
27 |
28 | this.handleClick(e)}>
29 | Add
30 |
31 |
32 | );
33 | }
34 |
35 | handleClick(e) {
36 | const node = this.refs.input;
37 | const text = node.value.trim();
38 | this.props.onAddClick(text);
39 | node.value = '';
40 | }
41 | }
42 |
43 | const FilterLink = ({ isActive, name, onClick }) => {
44 | if (isActive) {
45 | return {name} ;
46 | }
47 |
48 | return (
49 | { e.preventDefault(); onClick(); }}>
50 | {name}
51 |
52 | );
53 | };
54 |
55 | const Footer = ({ filter, onFilterChange }) => (
56 |
57 | Show:
58 | {' '}
59 | onFilterChange(Filters.SHOW_ALL)} />
63 | {', '}
64 | onFilterChange(Filters.SHOW_COMPLETED)} />
68 | {', '}
69 | onFilterChange(Filters.SHOW_ACTIVE)} />
73 |
74 | );
75 |
76 | const Todo = ({ onClick, completed, text }) => (
77 |
83 | {text}
84 |
85 | );
86 |
87 |
88 | const TodoList = ({ todos, onTodoClick }) => (
89 |
90 | {todos.map(todo =>
91 | onTodoClick(todo.id)} />
94 | )}
95 |
96 | );
97 |
98 | let nextTodoId = 0;
99 | const TodoApp = ({ dispatch, todos, visibilityFilter }) => {
100 | let visibleTodos = todos;
101 |
102 | switch (visibilityFilter) {
103 | case Filters.SHOW_COMPLETED:
104 | visibleTodos = todos.filter(todo => todo.completed);
105 | break;
106 | case Filters.SHOW_ACTIVE:
107 | visibleTodos = todos.filter(todo => !todo.completed);
108 | break;
109 | }
110 |
111 | return (
112 |
113 |
115 | dispatch({ type: ADD_TODO, text, id: nextTodoId++ })
116 | } />
117 |
120 | dispatch({ type: TOGGLE_TODO, id })
121 | } />
122 |
125 | dispatch({ type: SET_VISIBILITY_FILTER, filter })
126 | } />
127 |
128 | );
129 | };
130 |
131 | /*
132 | * Reducers
133 | */
134 |
135 | const visibilityFilter = (state = Filters.SHOW_ALL, action) => {
136 | switch (action.type) {
137 | case SET_VISIBILITY_FILTER:
138 | return action.filter;
139 | default:
140 | return state;
141 | }
142 | }
143 |
144 | const todos = (state = [], action) => {
145 | switch (action.type) {
146 | case ADD_TODO:
147 | return [...state, {
148 | text: action.text,
149 | id: action.id,
150 | completed: false
151 | }];
152 | case TOGGLE_TODO:
153 | return state.map(todo =>
154 | todo.id === action.id ?
155 | Object.assign({}, todo, { completed: !todo.completed }) :
156 | todo
157 | );
158 | default:
159 | return state;
160 | }
161 | }
162 |
163 | const todoApp = Redux.combineReducers({
164 | visibilityFilter,
165 | todos
166 | });
167 |
168 | /*
169 | * Go!
170 | */
171 |
172 | const store = Redux.createStore(todoApp);
173 | const dispatch = (action) => {
174 | store.dispatch(action);
175 | console.log('----------------') || displayInPreview('----------------');
176 | console.log('current state:') || displayInPreview('current state:');
177 | console.log(store.getState()) || displayInPreview(store.getState().visibilityFilter);
178 | }
179 | const render = () => {
180 | ReactDOM.render(
181 | ,
185 | document.getElementById('root')
186 | );
187 | }
188 | render();
189 | store.subscribe(render);
190 | console.log('current state:') || displayInPreview('current state:');
191 | console.log(store.getState()) || displayInPreview(store.getState().visibilityFilter);
192 |
193 | // noprotect
194 |
195 |
196 |
197 |
198 | // display in plunker preview
199 | function displayInPreview(string) {
200 | var newDiv = document.createElement("div");
201 | var newContent = document.createTextNode(string);
202 | newDiv.appendChild(newContent);
203 | document.body.appendChild(newDiv)
204 | }
--------------------------------------------------------------------------------
/02-react-redux-describing-state-changes-with-actions/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/02-react-redux-describing-state-changes-with-actions/app.css
--------------------------------------------------------------------------------
/02-react-redux-describing-state-changes-with-actions/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/02-react-redux-describing-state-changes-with-actions/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * We will be explaining the code below
3 | * in the following lessons. For now,
4 | * feel free to click around and notice
5 | * how the dispatched action is logged
6 | * to the console on every change.
7 | */
8 |
9 | const ADD_TODO = 'ADD_TODO';
10 | const TOGGLE_TODO = 'TOGGLE_TODO';
11 | const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';
12 |
13 | const Filters = {
14 | SHOW_ALL: 'SHOW_ALL',
15 | SHOW_COMPLETED: 'SHOW_COMPLETED',
16 | SHOW_ACTIVE: 'SHOW_ACTIVE'
17 | };
18 |
19 | /*
20 | * Components
21 | */
22 |
23 | class AddTodo extends React.Component {
24 | render() {
25 | return (
26 |
27 |
28 | this.handleClick(e)}>
29 | Add
30 |
31 |
32 | );
33 | }
34 |
35 | handleClick(e) {
36 | const node = this.refs.input;
37 | const text = node.value.trim();
38 | this.props.onAddClick(text);
39 | node.value = '';
40 | }
41 | }
42 |
43 | const FilterLink = ({ isActive, name, onClick }) => {
44 | if (isActive) {
45 | return {name} ;
46 | }
47 |
48 | return (
49 | { e.preventDefault(); onClick(); }}>
50 | {name}
51 |
52 | );
53 | };
54 |
55 | const Footer = ({ filter, onFilterChange }) => (
56 |
57 | Show:
58 | {' '}
59 | onFilterChange(Filters.SHOW_ALL)} />
63 | {', '}
64 | onFilterChange(Filters.SHOW_COMPLETED)} />
68 | {', '}
69 | onFilterChange(Filters.SHOW_ACTIVE)} />
73 |
74 | );
75 |
76 | const Todo = ({ onClick, completed, text }) => (
77 |
83 | {text}
84 |
85 | );
86 |
87 |
88 | const TodoList = ({ todos, onTodoClick }) => (
89 |
90 | {todos.map(todo =>
91 | onTodoClick(todo.id)} />
94 | )}
95 |
96 | );
97 |
98 | let nextTodoId = 0;
99 | const TodoApp = ({ dispatch, todos, visibilityFilter }) => {
100 | let visibleTodos = todos;
101 |
102 | switch (visibilityFilter) {
103 | case Filters.SHOW_COMPLETED:
104 | visibleTodos = todos.filter(todo => todo.completed);
105 | break;
106 | case Filters.SHOW_ACTIVE:
107 | visibleTodos = todos.filter(todo => !todo.completed);
108 | break;
109 | }
110 |
111 | return (
112 |
113 |
115 | dispatch({ type: ADD_TODO, text, id: nextTodoId++ })
116 | } />
117 |
120 | dispatch({ type: TOGGLE_TODO, id })
121 | } />
122 |
125 | dispatch({ type: SET_VISIBILITY_FILTER, filter })
126 | } />
127 |
128 | );
129 | };
130 |
131 | /*
132 | * Reducers
133 | */
134 |
135 | const visibilityFilter = (state = Filters.SHOW_ALL, action) => {
136 | switch (action.type) {
137 | case SET_VISIBILITY_FILTER:
138 | return action.filter;
139 | default:
140 | return state;
141 | }
142 | }
143 |
144 | const todos = (state = [], action) => {
145 | switch (action.type) {
146 | case ADD_TODO:
147 | return [...state, {
148 | text: action.text,
149 | id: action.id,
150 | completed: false
151 | }];
152 | case TOGGLE_TODO:
153 | return state.map(todo =>
154 | todo.id === action.id ?
155 | Object.assign({}, todo, { completed: !todo.completed }) :
156 | todo
157 | );
158 | default:
159 | return state;
160 | }
161 | }
162 |
163 | const todoApp = Redux.combineReducers({
164 | visibilityFilter,
165 | todos
166 | });
167 |
168 | /*
169 | * Go!
170 | */
171 |
172 | const store = Redux.createStore(todoApp);
173 | const dispatch = (action) => {
174 | console.log('----------------') || displayInPreview('----------------');
175 | console.log('dispatching action:') || displayInPreview('dispatching action:');
176 | console.log(action) || displayInPreview(action);
177 | store.dispatch(action);
178 | }
179 | const render = () => {
180 | ReactDOM.render(
181 | ,
185 | document.getElementById('root')
186 | );
187 | }
188 | render();
189 | store.subscribe(render);
190 | // noprotect
191 |
192 |
193 |
194 |
195 | // display in plunker preview
196 | function displayInPreview(string) {
197 | var newDiv = document.createElement("div");
198 | var newContent = document.createTextNode(string);
199 | newDiv.appendChild(newContent);
200 | document.body.appendChild(newDiv)
201 | }
--------------------------------------------------------------------------------
/03-react-redux-pure-and-impure-functions/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/03-react-redux-pure-and-impure-functions/app.css
--------------------------------------------------------------------------------
/03-react-redux-pure-and-impure-functions/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/03-react-redux-pure-and-impure-functions/script.jsx:
--------------------------------------------------------------------------------
1 | // Pure functions
2 | function square(x) {
3 | return x * x;
4 | }
5 | function squareAll(items) {
6 | return items.map(square);
7 | }
8 |
9 | // Impure functions
10 | function square(x) {
11 | updateXInDatabase(x);
12 | return x * x;
13 | }
14 | function squareAll(items) {
15 | for (let i = 0; i < items.length; i++) {
16 | items[i] = square(items[i]);
17 | }
18 | }
--------------------------------------------------------------------------------
/04-javascript-redux-the-reducer-function/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/04-javascript-redux-the-reducer-function/app.css
--------------------------------------------------------------------------------
/04-javascript-redux-the-reducer-function/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/04-javascript-redux-the-reducer-function/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * We will be explaining the code below
3 | * in the following lessons. For now,
4 | * feel free to click around and notice
5 | * how the previous state tree, the
6 | * dispatched action, and the next
7 | * state tree are logged to the console
8 | * on every change.
9 | */
10 |
11 | const ADD_TODO = 'ADD_TODO';
12 | const TOGGLE_TODO = 'TOGGLE_TODO';
13 | const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';
14 |
15 | const Filters = {
16 | SHOW_ALL: 'SHOW_ALL',
17 | SHOW_COMPLETED: 'SHOW_COMPLETED',
18 | SHOW_ACTIVE: 'SHOW_ACTIVE'
19 | };
20 |
21 | /*
22 | * Components
23 | */
24 |
25 | class AddTodo extends React.Component {
26 | render() {
27 | return (
28 |
29 |
30 | this.handleClick(e)}>
31 | Add
32 |
33 |
34 | );
35 | }
36 |
37 | handleClick(e) {
38 | const node = this.refs.input;
39 | const text = node.value.trim();
40 | this.props.onAddClick(text);
41 | node.value = '';
42 | }
43 | }
44 |
45 | const FilterLink = ({ isActive, name, onClick }) => {
46 | if (isActive) {
47 | return {name} ;
48 | }
49 |
50 | return (
51 | { e.preventDefault(); onClick(); }}>
52 | {name}
53 |
54 | );
55 | };
56 |
57 | const Footer = ({ filter, onFilterChange }) => (
58 |
59 | Show:
60 | {' '}
61 | onFilterChange(Filters.SHOW_ALL)} />
65 | {', '}
66 | onFilterChange(Filters.SHOW_COMPLETED)} />
70 | {', '}
71 | onFilterChange(Filters.SHOW_ACTIVE)} />
75 |
76 | );
77 |
78 | const Todo = ({ onClick, completed, text }) => (
79 |
85 | {text}
86 |
87 | );
88 |
89 |
90 | const TodoList = ({ todos, onTodoClick }) => (
91 |
92 | {todos.map(todo =>
93 | onTodoClick(todo.id)} />
96 | )}
97 |
98 | );
99 |
100 | let nextTodoId = 0;
101 | const TodoApp = ({ dispatch, todos, visibilityFilter }) => {
102 | let visibleTodos = todos;
103 |
104 | switch (visibilityFilter) {
105 | case Filters.SHOW_COMPLETED:
106 | visibleTodos = todos.filter(todo => todo.completed);
107 | break;
108 | case Filters.SHOW_ACTIVE:
109 | visibleTodos = todos.filter(todo => !todo.completed);
110 | break;
111 | }
112 |
113 | return (
114 |
115 |
117 | dispatch({ type: ADD_TODO, text, id: nextTodoId++ })
118 | } />
119 |
122 | dispatch({ type: TOGGLE_TODO, id })
123 | } />
124 |
127 | dispatch({ type: SET_VISIBILITY_FILTER, filter })
128 | } />
129 |
130 | );
131 | };
132 |
133 | /*
134 | * Reducers
135 | */
136 |
137 | const visibilityFilter = (state = Filters.SHOW_ALL, action) => {
138 | switch (action.type) {
139 | case SET_VISIBILITY_FILTER:
140 | return action.filter;
141 | default:
142 | return state;
143 | }
144 | }
145 |
146 | const todos = (state = [], action) => {
147 | switch (action.type) {
148 | case ADD_TODO:
149 | return [...state, {
150 | text: action.text,
151 | id: action.id,
152 | completed: false
153 | }];
154 | case TOGGLE_TODO:
155 | return state.map(todo =>
156 | todo.id === action.id ?
157 | Object.assign({}, todo, { completed: !todo.completed }) :
158 | todo
159 | );
160 | default:
161 | return state;
162 | }
163 | }
164 |
165 | const todoApp = Redux.combineReducers({
166 | visibilityFilter,
167 | todos
168 | });
169 |
170 | /*
171 | * Go!
172 | */
173 |
174 | const store = Redux.createStore(todoApp);
175 | const dispatch = (action) => {
176 | console.log('----------------') || displayInPreview('----------------');
177 | console.log('previous state:') || displayInPreview('previous state:');
178 | console.log(store.getState()) || displayInPreview(store.getState());
179 | console.log('dispatching action:') || displayInPreview('dispatching action:');
180 | console.log(action) || displayInPreview(action);
181 | store.dispatch(action) || displayInPreview(action);
182 | console.log('next state:') || displayInPreview('next state:');
183 | console.log(store.getState()) || displayInPreview(store.getState());
184 | };
185 | const render = () => {
186 | ReactDOM.render(
187 | ,
191 | document.getElementById('root')
192 | );
193 | }
194 | render();
195 | store.subscribe(render);
196 | console.log('initial state:') || displayInPreview('initial state:');
197 | console.log(store.getState()) || displayInPreview(store.getState().visibilityFilter);
198 | // noprotect
199 |
200 |
201 |
202 | // display in plunker preview
203 | function displayInPreview(string) {
204 | var newDiv = document.createElement("div");
205 | var newContent = document.createTextNode(string);
206 | newDiv.appendChild(newContent);
207 | document.body.appendChild(newDiv)
208 | }
--------------------------------------------------------------------------------
/05-react-redux-writing-a-counter-reducer-with-tests/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/05-react-redux-writing-a-counter-reducer-with-tests/app.css
--------------------------------------------------------------------------------
/05-react-redux-writing-a-counter-reducer-with-tests/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/05-react-redux-writing-a-counter-reducer-with-tests/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * Open the console tab
3 | * to see that the tests pass.
4 | */
5 |
6 | const counter = (state = 0, action) => {
7 | switch (action.type) {
8 | case 'INCREMENT':
9 | return state + 1;
10 | case 'DECREMENT':
11 | return state - 1;
12 | default:
13 | return state;
14 | }
15 | }
16 |
17 | expect(
18 | counter(0, { type: 'INCREMENT' })
19 | ).toEqual(1);
20 |
21 | expect(
22 | counter(1, { type: 'INCREMENT' })
23 | ).toEqual(2);
24 |
25 | expect(
26 | counter(2, { type: 'DECREMENT' })
27 | ).toEqual(1);
28 |
29 | expect(
30 | counter(1, { type: 'DECREMENT' })
31 | ).toEqual(0);
32 |
33 | expect(
34 | counter(1, { type: 'SOMETHING_ELSE' })
35 | ).toEqual(1);
36 |
37 | expect(
38 | counter(undefined, {})
39 | ).toEqual(0);
40 |
41 | console.log('Tests passed!') || displayInPreview('Tests passed!');
42 |
43 |
44 |
45 | // display in plunker preview
46 | function displayInPreview(string) {
47 | var newDiv = document.createElement("div");
48 | var newContent = document.createTextNode(string);
49 | newDiv.appendChild(newContent);
50 | document.body.appendChild(newDiv)
51 | }
--------------------------------------------------------------------------------
/06-react-redux-store-methods-getstate-dispatch-and-subscribe/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/06-react-redux-store-methods-getstate-dispatch-and-subscribe/app.css
--------------------------------------------------------------------------------
/06-react-redux-store-methods-getstate-dispatch-and-subscribe/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/06-react-redux-store-methods-getstate-dispatch-and-subscribe/script.jsx:
--------------------------------------------------------------------------------
1 | const counter = (state = 0, action) => {
2 | switch (action.type) {
3 | case 'INCREMENT':
4 | return state + 1;
5 | case 'DECREMENT':
6 | return state - 1;
7 | default:
8 | return state;
9 | }
10 | }
11 |
12 | const { createStore } = Redux;
13 | const store = createStore(counter);
14 |
15 | const render = () => {
16 | document.body.innerText = store.getState();
17 | };
18 |
19 | store.subscribe(render);
20 | render();
21 |
22 | document.addEventListener('click', () => {
23 | store.dispatch({ type: 'INCREMENT' });
24 | });
--------------------------------------------------------------------------------
/07-react-redux-implementing-store-from-scratch/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/07-react-redux-implementing-store-from-scratch/app.css
--------------------------------------------------------------------------------
/07-react-redux-implementing-store-from-scratch/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/07-react-redux-implementing-store-from-scratch/script.jsx:
--------------------------------------------------------------------------------
1 | const counter = (state = 0, action) => {
2 | switch (action.type) {
3 | case 'INCREMENT':
4 | return state + 1;
5 | case 'DECREMENT':
6 | return state - 1;
7 | default:
8 | return state;
9 | }
10 | }
11 |
12 | const createStore = (reducer) => {
13 | let state;
14 | let listeners = [];
15 |
16 | const getState = () => state;
17 |
18 | const dispatch = (action) => {
19 | state = reducer(state, action);
20 | listeners.forEach(listener => listener());
21 | };
22 |
23 | const subscribe = (listener) => {
24 | listeners.push(listener);
25 | return () => {
26 | listeners = listeners.filter(l => l !== listener);
27 | };
28 | };
29 |
30 | dispatch({});
31 |
32 | return { getState, dispatch, subscribe };
33 | };
34 |
35 | const store = createStore(counter);
36 |
37 | const render = () => {
38 | document.body.innerText = store.getState();
39 | };
40 |
41 | store.subscribe(render);
42 | render();
43 |
44 | document.addEventListener('click', () => {
45 | store.dispatch({ type: 'INCREMENT' });
46 | });
--------------------------------------------------------------------------------
/08-react-redux-react-counter-example/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/08-react-redux-react-counter-example/app.css
--------------------------------------------------------------------------------
/08-react-redux-react-counter-example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/08-react-redux-react-counter-example/script.jsx:
--------------------------------------------------------------------------------
1 | const counter = (state = 0, action) => {
2 | switch (action.type) {
3 | case 'INCREMENT':
4 | return state + 1;
5 | case 'DECREMENT':
6 | return state - 1;
7 | default:
8 | return state;
9 | }
10 | }
11 |
12 | const Counter = ({
13 | value,
14 | onIncrement,
15 | onDecrement
16 | }) => (
17 |
18 |
{value}
19 | +
20 | -
21 |
22 | );
23 |
24 | const { createStore } = Redux;
25 | const store = createStore(counter);
26 |
27 | const render = () => {
28 | ReactDOM.render(
29 |
32 | store.dispatch({
33 | type: 'INCREMENT'
34 | })
35 | }
36 | onDecrement={() =>
37 | store.dispatch({
38 | type: 'DECREMENT'
39 | })
40 | }
41 | />,
42 | document.getElementById('root')
43 | );
44 | };
45 |
46 | store.subscribe(render);
47 | render();
48 |
--------------------------------------------------------------------------------
/09-react-redux-avoiding-array-mutations-with-concat-slice-and-spread/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/09-react-redux-avoiding-array-mutations-with-concat-slice-and-spread/app.css
--------------------------------------------------------------------------------
/09-react-redux-avoiding-array-mutations-with-concat-slice-and-spread/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/09-react-redux-avoiding-array-mutations-with-concat-slice-and-spread/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * Open the console to see
3 | * that all tests have passed.
4 | */
5 |
6 | const addCounter = (list) => {
7 | return [...list, 0];
8 | };
9 |
10 | const removeCounter = (list, index) => {
11 | return [
12 | ...list.slice(0, index),
13 | ...list.slice(index + 1)
14 | ];
15 | };
16 |
17 | const incrementCounter = (list, index) => {
18 | return [
19 | ...list.slice(0, index),
20 | list[index] + 1,
21 | ...list.slice(index + 1)
22 | ];
23 | };
24 |
25 | const testAddCounter = () => {
26 | const listBefore = [];
27 | const listAfter = [0];
28 |
29 | deepFreeze(listBefore);
30 |
31 | expect(
32 | addCounter(listBefore)
33 | ).toEqual(listAfter);
34 | };
35 |
36 | const testRemoveCounter = () => {
37 | const listBefore = [0, 10, 20];
38 | const listAfter = [0, 20];
39 |
40 | deepFreeze(listBefore);
41 |
42 | expect(
43 | removeCounter(listBefore, 1)
44 | ).toEqual(listAfter);
45 | };
46 |
47 | const testIncrementCounter = () => {
48 | const listBefore = [0, 10, 20];
49 | const listAfter = [0, 11, 20];
50 |
51 | deepFreeze(listBefore);
52 |
53 | expect(
54 | incrementCounter(listBefore, 1)
55 | ).toEqual(listAfter);
56 | };
57 |
58 | testAddCounter();
59 | testRemoveCounter();
60 | testIncrementCounter();
61 |
62 | console.log('All tests passed.') || displayInPreview('All tests passed.');
63 |
64 |
65 |
66 |
67 | // display in plunker preview
68 | function displayInPreview(string) {
69 | var newDiv = document.createElement("div");
70 | var newContent = document.createTextNode(string);
71 | newDiv.appendChild(newContent);
72 | document.body.appendChild(newDiv)
73 | }
74 |
75 | // Function exported from deep-freeze lib
76 | function deepFreeze (o) {
77 | if (o===Object(o)) {
78 | Object.isFrozen(o) || Object.freeze(o)
79 | Object.getOwnPropertyNames(o).forEach(function (prop) {
80 | prop==='constructor'||deepFreeze(o[prop])
81 | })
82 | }
83 | return o
84 | }
--------------------------------------------------------------------------------
/10-react-redux-avoiding-object-mutations-with-object-assign-and-spread/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/10-react-redux-avoiding-object-mutations-with-object-assign-and-spread/app.css
--------------------------------------------------------------------------------
/10-react-redux-avoiding-object-mutations-with-object-assign-and-spread/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/10-react-redux-avoiding-object-mutations-with-object-assign-and-spread/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * Open the console to see
3 | * that the tests have passed.
4 | */
5 |
6 | const toggleTodo = (todo) => {
7 | return {
8 | ...todo,
9 | completed: !todo.completed
10 | };
11 | };
12 |
13 | const testToggleTodo = () => {
14 | const todoBefore = {
15 | id: 0,
16 | text: 'Learn Redux',
17 | completed: false
18 | };
19 | const todoAfter = {
20 | id: 0,
21 | text: 'Learn Redux',
22 | completed: true
23 | };
24 |
25 | deepFreeze(todoBefore);
26 |
27 | expect(
28 | toggleTodo(todoBefore)
29 | ).toEqual(todoAfter);
30 | };
31 |
32 | testToggleTodo();
33 | console.log('All tests passed.') || displayInPreview('All tests passed.');
34 |
35 |
36 |
37 | // display in plunker preview
38 | function displayInPreview(string) {
39 | var newDiv = document.createElement("div");
40 | var newContent = document.createTextNode(string);
41 | newDiv.appendChild(newContent);
42 | document.body.appendChild(newDiv)
43 | }
44 |
45 | // Function exported from deep-freeze lib
46 | function deepFreeze (o) {
47 | if (o===Object(o)) {
48 | Object.isFrozen(o) || Object.freeze(o)
49 | Object.getOwnPropertyNames(o).forEach(function (prop) {
50 | prop==='constructor'||deepFreeze(o[prop])
51 | })
52 | }
53 | return o
54 | }
--------------------------------------------------------------------------------
/11-react-redux-writing-a-todo-list-reducer-adding-a-todo/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/11-react-redux-writing-a-todo-list-reducer-adding-a-todo/app.css
--------------------------------------------------------------------------------
/11-react-redux-writing-a-todo-list-reducer-adding-a-todo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/11-react-redux-writing-a-todo-list-reducer-adding-a-todo/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * Open the console
3 | * to see that the tests pass.
4 | */
5 |
6 | const todos = (state = [], action) => {
7 | switch (action.type) {
8 | case 'ADD_TODO':
9 | return [
10 | ...state,
11 | {
12 | id: action.id,
13 | text: action.text,
14 | completed: false
15 | }
16 | ];
17 | default:
18 | return state;
19 | }
20 | };
21 |
22 | const testAddTodo = () => {
23 | const stateBefore = [];
24 | const action = {
25 | type: 'ADD_TODO',
26 | id: 0,
27 | text: 'Learn Redux'
28 | };
29 | const stateAfter = [
30 | {
31 | id: 0,
32 | text: 'Learn Redux',
33 | completed: false
34 | }
35 | ];
36 |
37 | deepFreeze(stateBefore);
38 | deepFreeze(action);
39 |
40 | expect(
41 | todos(stateBefore, action)
42 | ).toEqual(stateAfter);
43 | };
44 |
45 | testAddTodo();
46 | console.log('All tests passed.') || displayInPreview('All tests passed.');
47 |
48 |
49 |
50 |
51 | // display in plunker preview
52 | function displayInPreview(string) {
53 | var newDiv = document.createElement("div");
54 | var newContent = document.createTextNode(string);
55 | newDiv.appendChild(newContent);
56 | document.body.appendChild(newDiv)
57 | }
58 |
59 | // Function exported from deep-freeze lib
60 | function deepFreeze (o) {
61 | if (o===Object(o)) {
62 | Object.isFrozen(o) || Object.freeze(o)
63 | Object.getOwnPropertyNames(o).forEach(function (prop) {
64 | prop==='constructor'||deepFreeze(o[prop])
65 | })
66 | }
67 | return o
68 | }
--------------------------------------------------------------------------------
/12-react-redux-writing-a-todo-list-reducer-toggling-a-todo/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/12-react-redux-writing-a-todo-list-reducer-toggling-a-todo/app.css
--------------------------------------------------------------------------------
/12-react-redux-writing-a-todo-list-reducer-toggling-a-todo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/12-react-redux-writing-a-todo-list-reducer-toggling-a-todo/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * Open the console
3 | * to see that the tests pass.
4 | */
5 |
6 | const todos = (state = [], action) => {
7 | switch (action.type) {
8 | case 'ADD_TODO':
9 | return [
10 | ...state,
11 | {
12 | id: action.id,
13 | text: action.text,
14 | completed: false
15 | }
16 | ];
17 | case 'TOGGLE_TODO':
18 | return state.map(todo => {
19 | if (todo.id !== action.id) {
20 | return todo;
21 | }
22 |
23 | return {
24 | ...todo,
25 | completed: !todo.completed
26 | };
27 | });
28 | default:
29 | return state;
30 | }
31 | };
32 |
33 | const testAddTodo = () => {
34 | const stateBefore = [];
35 | const action = {
36 | type: 'ADD_TODO',
37 | id: 0,
38 | text: 'Learn Redux'
39 | };
40 | const stateAfter = [
41 | {
42 | id: 0,
43 | text: 'Learn Redux',
44 | completed: false
45 | }
46 | ];
47 |
48 | deepFreeze(stateBefore);
49 | deepFreeze(action);
50 |
51 | expect(
52 | todos(stateBefore, action)
53 | ).toEqual(stateAfter);
54 | };
55 |
56 | const testToggleTodo = () => {
57 | const stateBefore = [
58 | {
59 | id: 0,
60 | text: 'Learn Redux',
61 | completed: false
62 | },
63 | {
64 | id: 1,
65 | text: 'Go shopping',
66 | completed: false
67 | }
68 | ];
69 | const action = {
70 | type: 'TOGGLE_TODO',
71 | id: 1
72 | };
73 | const stateAfter = [
74 | {
75 | id: 0,
76 | text: 'Learn Redux',
77 | completed: false
78 | },
79 | {
80 | id: 1,
81 | text: 'Go shopping',
82 | completed: true
83 | }
84 | ];
85 |
86 | deepFreeze(stateBefore);
87 | deepFreeze(action);
88 |
89 | expect(
90 | todos(stateBefore, action)
91 | ).toEqual(stateAfter);
92 | };
93 |
94 |
95 | testAddTodo();
96 | testToggleTodo();
97 | console.log('All tests passed.') || displayInPreview('All tests passed.');
98 |
99 |
100 |
101 |
102 | // display in plunker preview
103 | function displayInPreview(string) {
104 | var newDiv = document.createElement("div");
105 | var newContent = document.createTextNode(string);
106 | newDiv.appendChild(newContent);
107 | document.body.appendChild(newDiv)
108 | }
109 |
110 | // Function exported from deep-freeze lib
111 | function deepFreeze (o) {
112 | if (o===Object(o)) {
113 | Object.isFrozen(o) || Object.freeze(o)
114 | Object.getOwnPropertyNames(o).forEach(function (prop) {
115 | prop==='constructor'||deepFreeze(o[prop])
116 | })
117 | }
118 | return o
119 | }
--------------------------------------------------------------------------------
/13-react-redux-reducer-composition-with-arrays/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/13-react-redux-reducer-composition-with-arrays/app.css
--------------------------------------------------------------------------------
/13-react-redux-reducer-composition-with-arrays/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/13-react-redux-reducer-composition-with-arrays/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * Open the console
3 | * to see that the tests pass.
4 | */
5 |
6 | const todo = (state, action) => {
7 | switch (action.type) {
8 | case 'ADD_TODO':
9 | return {
10 | id: action.id,
11 | text: action.text,
12 | completed: false
13 | };
14 | case 'TOGGLE_TODO':
15 | if (state.id !== action.id) {
16 | return state;
17 | }
18 |
19 | return {
20 | ...state,
21 | completed: !state.completed
22 | };
23 | default:
24 | return state;
25 | }
26 | };
27 |
28 | const todos = (state = [], action) => {
29 | switch (action.type) {
30 | case 'ADD_TODO':
31 | return [
32 | ...state,
33 | todo(undefined, action)
34 | ];
35 | case 'TOGGLE_TODO':
36 | return state.map(t => todo(t, action));
37 | default:
38 | return state;
39 | }
40 | };
41 |
42 | const testAddTodo = () => {
43 | const stateBefore = [];
44 | const action = {
45 | type: 'ADD_TODO',
46 | id: 0,
47 | text: 'Learn Redux'
48 | };
49 | const stateAfter = [
50 | {
51 | id: 0,
52 | text: 'Learn Redux',
53 | completed: false
54 | }
55 | ];
56 |
57 | deepFreeze(stateBefore);
58 | deepFreeze(action);
59 |
60 | expect(
61 | todos(stateBefore, action)
62 | ).toEqual(stateAfter);
63 | };
64 |
65 | const testToggleTodo = () => {
66 | const stateBefore = [
67 | {
68 | id: 0,
69 | text: 'Learn Redux',
70 | completed: false
71 | },
72 | {
73 | id: 1,
74 | text: 'Go shopping',
75 | completed: false
76 | }
77 | ];
78 | const action = {
79 | type: 'TOGGLE_TODO',
80 | id: 1
81 | };
82 | const stateAfter = [
83 | {
84 | id: 0,
85 | text: 'Learn Redux',
86 | completed: false
87 | },
88 | {
89 | id: 1,
90 | text: 'Go shopping',
91 | completed: true
92 | }
93 | ];
94 |
95 | deepFreeze(stateBefore);
96 | deepFreeze(action);
97 |
98 | expect(
99 | todos(stateBefore, action)
100 | ).toEqual(stateAfter);
101 | };
102 |
103 |
104 | testAddTodo();
105 | testToggleTodo();
106 | console.log('All tests passed.') || displayInPreview('All tests passed.');
107 |
108 |
109 |
110 | // display in plunker preview
111 | function displayInPreview(string) {
112 | var newDiv = document.createElement("div");
113 | var newContent = document.createTextNode(string);
114 | newDiv.appendChild(newContent);
115 | document.body.appendChild(newDiv)
116 | }
117 |
118 | // Function exported from deep-freeze lib
119 | function deepFreeze (o) {
120 | if (o===Object(o)) {
121 | Object.isFrozen(o) || Object.freeze(o)
122 | Object.getOwnPropertyNames(o).forEach(function (prop) {
123 | prop==='constructor'||deepFreeze(o[prop])
124 | })
125 | }
126 | return o
127 | }
--------------------------------------------------------------------------------
/14-react-redux-reducer-composition-with-objects/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/14-react-redux-reducer-composition-with-objects/app.css
--------------------------------------------------------------------------------
/14-react-redux-reducer-composition-with-objects/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Open console to view results!
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/14-react-redux-reducer-composition-with-objects/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * Open the console
3 | * to see the state log.
4 | */
5 |
6 | const todo = (state, action) => {
7 | switch (action.type) {
8 | case 'ADD_TODO':
9 | return {
10 | id: action.id,
11 | text: action.text,
12 | completed: false
13 | };
14 | case 'TOGGLE_TODO':
15 | if (state.id !== action.id) {
16 | return state;
17 | }
18 |
19 | return {
20 | ...state,
21 | completed: !state.completed
22 | };
23 | default:
24 | return state;
25 | }
26 | };
27 |
28 | const todos = (state = [], action) => {
29 | switch (action.type) {
30 | case 'ADD_TODO':
31 | return [
32 | ...state,
33 | todo(undefined, action)
34 | ];
35 | case 'TOGGLE_TODO':
36 | return state.map(t => todo(t, action));
37 | default:
38 | return state;
39 | }
40 | };
41 |
42 | const visibilityFilter = (
43 | state = 'SHOW_ALL',
44 | action
45 | ) => {
46 | switch (action.type) {
47 | case 'SET_VISIBILITY_FILTER':
48 | return action.filter;
49 | default:
50 | return state;
51 | }
52 | };
53 |
54 | const todoApp = (state = {}, action) => {
55 | return {
56 | todos: todos(
57 | state.todos,
58 | action
59 | ),
60 | visibilityFilter: visibilityFilter(
61 | state.visibilityFilter,
62 | action
63 | )
64 | };
65 | };
66 |
67 | const { createStore } = Redux;
68 | const store = createStore(todoApp);
69 |
70 | console.log('Initial state:');
71 | console.log(store.getState());
72 | console.log('--------------');
73 |
74 | console.log('Dispatching ADD_TODO.')
75 | store.dispatch({
76 | type: 'ADD_TODO',
77 | id: 0,
78 | text: 'Learn Redux'
79 | });
80 | console.log('Current state:');
81 | console.log(store.getState());
82 | console.log('--------------');
83 |
84 | console.log('Dispatching ADD_TODO.');
85 | store.dispatch({
86 | type: 'ADD_TODO',
87 | id: 1,
88 | text: 'Go shopping'
89 | });
90 | console.log('Current state:');
91 | console.log(store.getState());
92 | console.log('--------------');
93 |
94 | console.log('Dispatching TOGGLE_TODO.');
95 | store.dispatch({
96 | type: 'TOGGLE_TODO',
97 | id: 0
98 | });
99 | console.log('Current state:');
100 | console.log(store.getState());
101 | console.log('--------------');
102 |
103 | console.log('Dispatching SET_VISIBILITY_FILTER');
104 | store.dispatch({
105 | type: 'SET_VISIBILITY_FILTER',
106 | filter: 'SHOW_COMPLETED'
107 | });
108 | console.log('Current state:');
109 | console.log(store.getState());
110 | console.log('--------------');
111 |
112 |
113 |
114 | // display in plunker preview
115 | function displayInPreview(string) {
116 | var newDiv = document.createElement("div");
117 | var newContent = document.createTextNode(string);
118 | newDiv.appendChild(newContent);
119 | document.body.appendChild(newDiv)
120 | }
121 |
--------------------------------------------------------------------------------
/15-react-redux-reducer-composition-with-combinereducers/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/15-react-redux-reducer-composition-with-combinereducers/app.css
--------------------------------------------------------------------------------
/15-react-redux-reducer-composition-with-combinereducers/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Open browser console to view full results!
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/15-react-redux-reducer-composition-with-combinereducers/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * Open the console
3 | * to see the state log.
4 | */
5 |
6 | const todo = (state, action) => {
7 | switch (action.type) {
8 | case 'ADD_TODO':
9 | return {
10 | id: action.id,
11 | text: action.text,
12 | completed: false
13 | };
14 | case 'TOGGLE_TODO':
15 | if (state.id !== action.id) {
16 | return state;
17 | }
18 |
19 | return {
20 | ...state,
21 | completed: !state.completed
22 | };
23 | default:
24 | return state;
25 | }
26 | };
27 |
28 | const todos = (state = [], action) => {
29 | switch (action.type) {
30 | case 'ADD_TODO':
31 | return [
32 | ...state,
33 | todo(undefined, action)
34 | ];
35 | case 'TOGGLE_TODO':
36 | return state.map(t => todo(t, action));
37 | default:
38 | return state;
39 | }
40 | };
41 |
42 | const visibilityFilter = (
43 | state = 'SHOW_ALL',
44 | action
45 | ) => {
46 | switch (action.type) {
47 | case 'SET_VISIBILITY_FILTER':
48 | return action.filter;
49 | default:
50 | return state;
51 | }
52 | };
53 |
54 | const { combineReducers } = Redux;
55 | const todoApp = combineReducers({
56 | todos,
57 | visibilityFilter
58 | });
59 |
60 | const { createStore } = Redux;
61 | const store = createStore(todoApp);
62 |
63 | console.log('Initial state:') || displayInPreview('Initial state:');
64 | console.log(store.getState()) || displayInPreview(store.getState().visibilityFilter);
65 | console.log('--------------') || displayInPreview('--------------');
66 |
67 |
68 | console.log('Dispatching ADD_TODO.') || displayInPreview('Dispatching ADD_TODO.');
69 | store.dispatch({
70 | type: 'ADD_TODO',
71 | id: 0,
72 | text: 'Learn Redux'
73 | });
74 | console.log('Initial state:') || displayInPreview('Initial state:');
75 | console.log(store.getState()) || displayInPreview(store.getState().visibilityFilter);
76 | console.log('--------------') || displayInPreview('--------------');
77 |
78 |
79 | console.log('Dispatching ADD_TODO.') || displayInPreview('Dispatching ADD_TODO.');
80 | store.dispatch({
81 | type: 'ADD_TODO',
82 | id: 1,
83 | text: 'Go shopping'
84 | });
85 | console.log('Initial state:') || displayInPreview('Initial state:');
86 | console.log(store.getState()) || displayInPreview(store.getState().visibilityFilter);
87 | console.log('--------------') || displayInPreview('--------------');
88 |
89 |
90 | console.log('Dispatching TOGGLE_TODO.') || displayInPreview('Dispatching TOGGLE_TODO.');
91 | store.dispatch({
92 | type: 'TOGGLE_TODO',
93 | id: 0
94 | });
95 | console.log('Initial state:') || displayInPreview('Initial state:');
96 | console.log(store.getState()) || displayInPreview(store.getState().visibilityFilter);
97 | console.log('--------------') || displayInPreview('--------------');
98 |
99 |
100 | console.log('Dispatching SET_VISIBILITY_FILTER') || displayInPreview('Dispatching SET_VISIBILITY_FILTER');
101 | store.dispatch({
102 | type: 'SET_VISIBILITY_FILTER',
103 | filter: 'SHOW_COMPLETED'
104 | });
105 | console.log('Initial state:') || displayInPreview('Initial state:');
106 | console.log(store.getState()) || displayInPreview(store.getState().visibilityFilter);
107 | console.log('--------------') || displayInPreview('--------------');
108 |
109 |
110 |
111 | // display in plunker preview
112 | function displayInPreview(string) {
113 | var newDiv = document.createElement("div");
114 | var newContent = document.createTextNode(string);
115 | newDiv.appendChild(newContent);
116 | document.body.appendChild(newDiv)
117 | }
--------------------------------------------------------------------------------
/16-javascript-redux-implementing-combinereducers-from-scratch/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/16-javascript-redux-implementing-combinereducers-from-scratch/app.css
--------------------------------------------------------------------------------
/16-javascript-redux-implementing-combinereducers-from-scratch/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | JS Bin
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/16-javascript-redux-implementing-combinereducers-from-scratch/script.jsx:
--------------------------------------------------------------------------------
1 | /*
2 | * Open the console
3 | * to see the state log.
4 | */
5 |
6 | const todo = (state, action) => {
7 | switch (action.type) {
8 | case 'ADD_TODO':
9 | return {
10 | id: action.id,
11 | text: action.text,
12 | completed: false
13 | };
14 | case 'TOGGLE_TODO':
15 | if (state.id !== action.id) {
16 | return state;
17 | }
18 |
19 | return {
20 | ...state,
21 | completed: !state.completed
22 | };
23 | default:
24 | return state;
25 | }
26 | };
27 |
28 | const todos = (state = [], action) => {
29 | switch (action.type) {
30 | case 'ADD_TODO':
31 | return [
32 | ...state,
33 | todo(undefined, action)
34 | ];
35 | case 'TOGGLE_TODO':
36 | return state.map(t => todo(t, action));
37 | default:
38 | return state;
39 | }
40 | };
41 |
42 | const visibilityFilter = (
43 | state = 'SHOW_ALL',
44 | action
45 | ) => {
46 | switch (action.type) {
47 | case 'SET_VISIBILITY_FILTER':
48 | return action.filter;
49 | default:
50 | return state;
51 | }
52 | };
53 |
54 | const combineReducers = (reducers) => {
55 | return (state = {}, action) => {
56 | return Object.keys(reducers).reduce(
57 | (nextState, key) => {
58 | nextState[key] = reducers[key](
59 | state[key],
60 | action
61 | );
62 | return nextState;
63 | },
64 | {}
65 | );
66 | };
67 | };
68 |
69 | const todoApp = combineReducers({
70 | todos,
71 | visibilityFilter
72 | });
73 |
74 | const { createStore } = Redux;
75 | const store = createStore(todoApp);
76 |
77 | console.log('Initial state:');
78 | console.log(store.getState());
79 | console.log('--------------');
80 |
81 | console.log('Dispatching ADD_TODO.');
82 | store.dispatch({
83 | type: 'ADD_TODO',
84 | id: 0,
85 | text: 'Learn Redux'
86 | });
87 | console.log('Current state:');
88 | console.log(store.getState());
89 | console.log('--------------');
90 |
91 | console.log('Dispatching ADD_TODO.');
92 | store.dispatch({
93 | type: 'ADD_TODO',
94 | id: 1,
95 | text: 'Go shopping'
96 | });
97 | console.log('Current state:');
98 | console.log(store.getState());
99 | console.log('--------------');
100 |
101 | console.log('Dispatching TOGGLE_TODO.');
102 | store.dispatch({
103 | type: 'TOGGLE_TODO',
104 | id: 0
105 | });
106 | console.log('Current state:');
107 | console.log(store.getState());
108 | console.log('--------------');
109 |
110 | console.log('Dispatching SET_VISIBILITY_FILTER');
111 | store.dispatch({
112 | type: 'SET_VISIBILITY_FILTER',
113 | filter: 'SHOW_COMPLETED'
114 | });
115 | console.log('Current state:');
116 | console.log(store.getState());
117 | console.log('--------------');
--------------------------------------------------------------------------------
/17-react-redux-react-todo-list-example-adding-a-todo/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/17-react-redux-react-todo-list-example-adding-a-todo/app.css
--------------------------------------------------------------------------------
/17-react-redux-react-todo-list-example-adding-a-todo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/17-react-redux-react-todo-list-example-adding-a-todo/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { createStore } = Redux;
58 | const store = createStore(todoApp);
59 |
60 | const { Component } = React;
61 |
62 | let nextTodoId = 0;
63 | class TodoApp extends Component {
64 | render() {
65 | return (
66 |
67 |
{
68 | this.input = node;
69 | }} />
70 |
{
71 | store.dispatch({
72 | type: 'ADD_TODO',
73 | text: this.input.value,
74 | id: nextTodoId++
75 | });
76 | this.input.value = '';
77 | }}>
78 | Add Todo
79 |
80 |
81 | {this.props.todos.map(todo =>
82 |
83 | {todo.text}
84 |
85 | )}
86 |
87 |
88 | );
89 | }
90 | }
91 |
92 | const render = () => {
93 | ReactDOM.render(
94 | ,
97 | document.getElementById('root')
98 | );
99 | };
100 |
101 | store.subscribe(render);
102 | render();
--------------------------------------------------------------------------------
/18-react-redux-react-todo-list-example-toggling-a-todo/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/18-react-redux-react-todo-list-example-toggling-a-todo/app.css
--------------------------------------------------------------------------------
/18-react-redux-react-todo-list-example-toggling-a-todo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/18-react-redux-react-todo-list-example-toggling-a-todo/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { createStore } = Redux;
58 | const store = createStore(todoApp);
59 |
60 | const { Component } = React;
61 |
62 | let nextTodoId = 0;
63 | class TodoApp extends Component {
64 | render() {
65 | return (
66 |
67 |
{
68 | this.input = node;
69 | }} />
70 |
{
71 | store.dispatch({
72 | type: 'ADD_TODO',
73 | text: this.input.value,
74 | id: nextTodoId++
75 | });
76 | this.input.value = '';
77 | }}>
78 | Add Todo
79 |
80 |
81 | {this.props.todos.map(todo =>
82 | {
84 | store.dispatch({
85 | type: 'TOGGLE_TODO',
86 | id: todo.id
87 | });
88 | }}
89 | style={{
90 | textDecoration:
91 | todo.completed ?
92 | 'line-through' :
93 | 'none'
94 | }}>
95 | {todo.text}
96 |
97 | )}
98 |
99 |
100 | );
101 | }
102 | }
103 |
104 | const render = () => {
105 | ReactDOM.render(
106 | ,
109 | document.getElementById('root')
110 | );
111 | };
112 |
113 | store.subscribe(render);
114 | render();
--------------------------------------------------------------------------------
/19-react-redux-react-todo-list-example-filtering-todos/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/19-react-redux-react-todo-list-example-filtering-todos/app.css
--------------------------------------------------------------------------------
/19-react-redux-react-todo-list-example-filtering-todos/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/19-react-redux-react-todo-list-example-filtering-todos/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { createStore } = Redux;
58 | const store = createStore(todoApp);
59 |
60 | const { Component } = React;
61 |
62 | const FilterLink = ({
63 | filter,
64 | currentFilter,
65 | children
66 | }) => {
67 | if (filter === currentFilter) {
68 | return {children} ;
69 | }
70 |
71 | return (
72 | {
74 | e.preventDefault();
75 | store.dispatch({
76 | type: 'SET_VISIBILITY_FILTER',
77 | filter
78 | });
79 | }}
80 | >
81 | {children}
82 |
83 | );
84 | };
85 |
86 | const getVisibleTodos = (
87 | todos,
88 | filter
89 | ) => {
90 | switch (filter) {
91 | case 'SHOW_ALL':
92 | return todos;
93 | case 'SHOW_COMPLETED':
94 | return todos.filter(
95 | t => t.completed
96 | );
97 | case 'SHOW_ACTIVE':
98 | return todos.filter(
99 | t => !t.completed
100 | );
101 | }
102 | }
103 |
104 | let nextTodoId = 0;
105 | class TodoApp extends Component {
106 | render() {
107 | const {
108 | todos,
109 | visibilityFilter
110 | } = this.props;
111 | const visibleTodos = getVisibleTodos(
112 | todos,
113 | visibilityFilter
114 | );
115 | return (
116 |
117 |
{
118 | this.input = node;
119 | }} />
120 |
{
121 | store.dispatch({
122 | type: 'ADD_TODO',
123 | text: this.input.value,
124 | id: nextTodoId++
125 | });
126 | this.input.value = '';
127 | }}>
128 | Add Todo
129 |
130 |
131 | {visibleTodos.map(todo =>
132 | {
134 | store.dispatch({
135 | type: 'TOGGLE_TODO',
136 | id: todo.id
137 | });
138 | }}
139 | style={{
140 | textDecoration:
141 | todo.completed ?
142 | 'line-through' :
143 | 'none'
144 | }}>
145 | {todo.text}
146 |
147 | )}
148 |
149 |
150 | Show:
151 | {' '}
152 |
156 | All
157 |
158 | {', '}
159 |
163 | Active
164 |
165 | {', '}
166 |
170 | Completed
171 |
172 |
173 |
174 | );
175 | }
176 | }
177 |
178 | const render = () => {
179 | ReactDOM.render(
180 | ,
183 | document.getElementById('root')
184 | );
185 | };
186 |
187 | store.subscribe(render);
188 | render();
--------------------------------------------------------------------------------
/20-react-redux-extracting-presentational-components-todo-todolist/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/20-react-redux-extracting-presentational-components-todo-todolist/app.css
--------------------------------------------------------------------------------
/20-react-redux-extracting-presentational-components-todo-todolist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/20-react-redux-extracting-presentational-components-todo-todolist/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { createStore } = Redux;
58 | const store = createStore(todoApp);
59 |
60 | const { Component } = React;
61 |
62 | const FilterLink = ({
63 | filter,
64 | currentFilter,
65 | children
66 | }) => {
67 | if (filter === currentFilter) {
68 | return {children} ;
69 | }
70 |
71 | return (
72 | {
74 | e.preventDefault();
75 | store.dispatch({
76 | type: 'SET_VISIBILITY_FILTER',
77 | filter
78 | });
79 | }}
80 | >
81 | {children}
82 |
83 | );
84 | };
85 |
86 | const Todo = ({
87 | onClick,
88 | completed,
89 | text
90 | }) => (
91 |
100 | {text}
101 |
102 | );
103 |
104 | const TodoList = ({
105 | todos,
106 | onTodoClick
107 | }) => (
108 |
109 | {todos.map(todo =>
110 | onTodoClick(todo.id)}
114 | />
115 | )}
116 |
117 | );
118 |
119 | const getVisibleTodos = (
120 | todos,
121 | filter
122 | ) => {
123 | switch (filter) {
124 | case 'SHOW_ALL':
125 | return todos;
126 | case 'SHOW_COMPLETED':
127 | return todos.filter(
128 | t => t.completed
129 | );
130 | case 'SHOW_ACTIVE':
131 | return todos.filter(
132 | t => !t.completed
133 | );
134 | }
135 | }
136 |
137 | let nextTodoId = 0;
138 | class TodoApp extends Component {
139 | render() {
140 | const {
141 | todos,
142 | visibilityFilter
143 | } = this.props;
144 | const visibleTodos = getVisibleTodos(
145 | todos,
146 | visibilityFilter
147 | );
148 | return (
149 |
150 |
{
151 | this.input = node;
152 | }} />
153 |
{
154 | store.dispatch({
155 | type: 'ADD_TODO',
156 | text: this.input.value,
157 | id: nextTodoId++
158 | });
159 | this.input.value = '';
160 | }}>
161 | Add Todo
162 |
163 |
166 | store.dispatch({
167 | type: 'TOGGLE_TODO',
168 | id
169 | })
170 | }
171 | />
172 |
173 | Show:
174 | {' '}
175 |
179 | All
180 |
181 | {', '}
182 |
186 | Active
187 |
188 | {', '}
189 |
193 | Completed
194 |
195 |
196 |
197 | );
198 | }
199 | }
200 |
201 | const render = () => {
202 | ReactDOM.render(
203 | ,
206 | document.getElementById('root')
207 | );
208 | };
209 |
210 | store.subscribe(render);
211 | render();
--------------------------------------------------------------------------------
/21-react-redux-extracting-presentational-components-addtodo-footer-filterlink/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/21-react-redux-extracting-presentational-components-addtodo-footer-filterlink/app.css
--------------------------------------------------------------------------------
/21-react-redux-extracting-presentational-components-addtodo-footer-filterlink/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/21-react-redux-extracting-presentational-components-addtodo-footer-filterlink/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 | return {
14 | ...state,
15 | completed: !state.completed
16 | };
17 | default:
18 | return state;
19 | }
20 | };
21 |
22 | const todos = (state = [], action) => {
23 | switch (action.type) {
24 | case 'ADD_TODO':
25 | return [
26 | ...state,
27 | todo(undefined, action)
28 | ];
29 | case 'TOGGLE_TODO':
30 | return state.map(t =>
31 | todo(t, action)
32 | );
33 | default:
34 | return state;
35 | }
36 | };
37 |
38 | const visibilityFilter = (
39 | state = 'SHOW_ALL',
40 | action
41 | ) => {
42 | switch (action.type) {
43 | case 'SET_VISIBILITY_FILTER':
44 | return action.filter;
45 | default:
46 | return state;
47 | }
48 | };
49 |
50 | const { combineReducers } = Redux;
51 | const todoApp = combineReducers({
52 | todos,
53 | visibilityFilter
54 | });
55 |
56 | const { createStore } = Redux;
57 | const store = createStore(todoApp);
58 |
59 | const { Component } = React;
60 |
61 | const FilterLink = ({
62 | filter,
63 | currentFilter,
64 | children,
65 | onClick
66 | }) => {
67 | if (filter === currentFilter) {
68 | return {children} ;
69 | }
70 |
71 | return (
72 | {
74 | e.preventDefault();
75 | onClick(filter);
76 | }}
77 | >
78 | {children}
79 |
80 | );
81 | };
82 |
83 | const Footer = ({
84 | visibilityFilter,
85 | onFilterClick
86 | }) => (
87 |
88 | Show:
89 | {' '}
90 |
95 | All
96 |
97 | {', '}
98 |
103 | Active
104 |
105 | {', '}
106 |
111 | Completed
112 |
113 |
114 | );
115 |
116 | const Todo = ({
117 | onClick,
118 | completed,
119 | text
120 | }) => (
121 |
130 | {text}
131 |
132 | );
133 |
134 | const TodoList = ({
135 | todos,
136 | onTodoClick
137 | }) => (
138 |
139 | {todos.map(todo =>
140 | onTodoClick(todo.id)}
144 | />
145 | )}
146 |
147 | );
148 |
149 | const AddTodo = ({
150 | onAddClick
151 | }) => {
152 | let input;
153 |
154 | return (
155 |
156 | {
157 | input = node;
158 | }} />
159 | {
160 | onAddClick(input.value);
161 | input.value = '';
162 | }}>
163 | Add Todo
164 |
165 |
166 | );
167 | };
168 |
169 | const getVisibleTodos = (
170 | todos,
171 | filter
172 | ) => {
173 | switch (filter) {
174 | case 'SHOW_ALL':
175 | return todos;
176 | case 'SHOW_COMPLETED':
177 | return todos.filter(
178 | t => t.completed
179 | );
180 | case 'SHOW_ACTIVE':
181 | return todos.filter(
182 | t => !t.completed
183 | );
184 | }
185 | }
186 |
187 | let nextTodoId = 0;
188 | const TodoApp = ({
189 | todos,
190 | visibilityFilter
191 | }) => (
192 |
193 |
195 | store.dispatch({
196 | type: 'ADD_TODO',
197 | id: nextTodoId++,
198 | text
199 | })
200 | }
201 | />
202 |
210 | store.dispatch({
211 | type: 'TOGGLE_TODO',
212 | id
213 | })
214 | }
215 | />
216 |
219 | store.dispatch({
220 | type: 'SET_VISIBILITY_FILTER',
221 | filter
222 | })
223 | }
224 | />
225 |
226 | );
227 |
228 | const render = () => {
229 | ReactDOM.render(
230 | ,
233 | document.getElementById('root')
234 | );
235 | };
236 |
237 | store.subscribe(render);
238 | render();
--------------------------------------------------------------------------------
/22-react-redux-extracting-container-components-filterlink/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/22-react-redux-extracting-container-components-filterlink/app.css
--------------------------------------------------------------------------------
/22-react-redux-extracting-container-components-filterlink/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/22-react-redux-extracting-container-components-filterlink/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { createStore } = Redux;
58 | const store = createStore(todoApp);
59 |
60 | const { Component } = React;
61 |
62 | const Link = ({
63 | active,
64 | children,
65 | onClick
66 | }) => {
67 | if (active) {
68 | return {children} ;
69 | }
70 |
71 | return (
72 | {
74 | e.preventDefault();
75 | onClick();
76 | }}
77 | >
78 | {children}
79 |
80 | );
81 | };
82 |
83 | class FilterLink extends Component {
84 | componentDidMount() {
85 | this.unsubscribe = store.subscribe(() =>
86 | this.forceUpdate()
87 | );
88 | }
89 |
90 | componentWillUnmount() {
91 | this.unsubscribe();
92 | }
93 |
94 | render() {
95 | const props = this.props;
96 | const state = store.getState();
97 |
98 | return (
99 |
105 | store.dispatch({
106 | type: 'SET_VISIBILITY_FILTER',
107 | filter: props.filter
108 | })
109 | }
110 | >
111 | {props.children}
112 |
113 | );
114 | }
115 | }
116 |
117 | const Footer = () => (
118 |
119 | Show:
120 | {' '}
121 |
124 | All
125 |
126 | {', '}
127 |
130 | Active
131 |
132 | {', '}
133 |
136 | Completed
137 |
138 |
139 | );
140 |
141 | const Todo = ({
142 | onClick,
143 | completed,
144 | text
145 | }) => (
146 |
155 | {text}
156 |
157 | );
158 |
159 | const TodoList = ({
160 | todos,
161 | onTodoClick
162 | }) => (
163 |
164 | {todos.map(todo =>
165 | onTodoClick(todo.id)}
169 | />
170 | )}
171 |
172 | );
173 |
174 | const AddTodo = ({
175 | onAddClick
176 | }) => {
177 | let input;
178 |
179 | return (
180 |
181 | {
182 | input = node;
183 | }} />
184 | {
185 | onAddClick(input.value);
186 | input.value = '';
187 | }}>
188 | Add Todo
189 |
190 |
191 | );
192 | };
193 |
194 | const getVisibleTodos = (
195 | todos,
196 | filter
197 | ) => {
198 | switch (filter) {
199 | case 'SHOW_ALL':
200 | return todos;
201 | case 'SHOW_COMPLETED':
202 | return todos.filter(
203 | t => t.completed
204 | );
205 | case 'SHOW_ACTIVE':
206 | return todos.filter(
207 | t => !t.completed
208 | );
209 | }
210 | }
211 |
212 | let nextTodoId = 0;
213 | const TodoApp = ({
214 | todos,
215 | visibilityFilter
216 | }) => (
217 |
218 |
220 | store.dispatch({
221 | type: 'ADD_TODO',
222 | id: nextTodoId++,
223 | text
224 | })
225 | }
226 | />
227 |
235 | store.dispatch({
236 | type: 'TOGGLE_TODO',
237 | id
238 | })
239 | }
240 | />
241 |
242 |
243 | );
244 |
245 | const render = () => {
246 | ReactDOM.render(
247 | ,
250 | document.getElementById('root')
251 | );
252 | };
253 |
254 | store.subscribe(render);
255 | render();
--------------------------------------------------------------------------------
/23-react-redux-extracting-container-components-visibletodolist-addtodo/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/23-react-redux-extracting-container-components-visibletodolist-addtodo/app.css
--------------------------------------------------------------------------------
/23-react-redux-extracting-container-components-visibletodolist-addtodo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/23-react-redux-extracting-container-components-visibletodolist-addtodo/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { createStore } = Redux;
58 | const store = createStore(todoApp);
59 |
60 | const { Component } = React;
61 |
62 | const Link = ({
63 | active,
64 | children,
65 | onClick
66 | }) => {
67 | if (active) {
68 | return {children} ;
69 | }
70 |
71 | return (
72 | {
74 | e.preventDefault();
75 | onClick();
76 | }}
77 | >
78 | {children}
79 |
80 | );
81 | };
82 |
83 | class FilterLink extends Component {
84 | componentDidMount() {
85 | this.unsubscribe = store.subscribe(() =>
86 | this.forceUpdate()
87 | );
88 | }
89 |
90 | componentWillUnmount() {
91 | this.unsubscribe();
92 | }
93 |
94 | render() {
95 | const props = this.props;
96 | const state = store.getState();
97 |
98 | return (
99 |
105 | store.dispatch({
106 | type: 'SET_VISIBILITY_FILTER',
107 | filter: props.filter
108 | })
109 | }
110 | >
111 | {props.children}
112 |
113 | );
114 | }
115 | }
116 |
117 | const Footer = () => (
118 |
119 | Show:
120 | {' '}
121 |
122 | All
123 |
124 | {', '}
125 |
126 | Active
127 |
128 | {', '}
129 |
130 | Completed
131 |
132 |
133 | );
134 |
135 | const Todo = ({
136 | onClick,
137 | completed,
138 | text
139 | }) => (
140 |
149 | {text}
150 |
151 | );
152 |
153 | const TodoList = ({
154 | todos,
155 | onTodoClick
156 | }) => (
157 |
158 | {todos.map(todo =>
159 | onTodoClick(todo.id)}
163 | />
164 | )}
165 |
166 | );
167 |
168 | let nextTodoId = 0;
169 | const AddTodo = () => {
170 | let input;
171 |
172 | return (
173 |
174 | {
175 | input = node;
176 | }} />
177 | {
178 | store.dispatch({
179 | type: 'ADD_TODO',
180 | id: nextTodoId++,
181 | text: input.value
182 | })
183 | input.value = '';
184 | }}>
185 | Add Todo
186 |
187 |
188 | );
189 | };
190 |
191 | const getVisibleTodos = (
192 | todos,
193 | filter
194 | ) => {
195 | switch (filter) {
196 | case 'SHOW_ALL':
197 | return todos;
198 | case 'SHOW_COMPLETED':
199 | return todos.filter(
200 | t => t.completed
201 | );
202 | case 'SHOW_ACTIVE':
203 | return todos.filter(
204 | t => !t.completed
205 | );
206 | }
207 | }
208 |
209 | class VisibleTodoList extends Component {
210 | componentDidMount() {
211 | this.unsubscribe = store.subscribe(() =>
212 | this.forceUpdate()
213 | );
214 | }
215 |
216 | componentWillUnmount() {
217 | this.unsubscribe();
218 | }
219 |
220 | render() {
221 | const props = this.props;
222 | const state = store.getState();
223 |
224 | return (
225 |
233 | store.dispatch({
234 | type: 'TOGGLE_TODO',
235 | id
236 | })
237 | }
238 | />
239 | );
240 | }
241 | }
242 |
243 | const TodoApp = () => (
244 |
249 | );
250 |
251 | ReactDOM.render(
252 | ,
253 | document.getElementById('root')
254 | );
--------------------------------------------------------------------------------
/24-react-redux-passing-the-store-down-explicitly-via-props/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/24-react-redux-passing-the-store-down-explicitly-via-props/app.css
--------------------------------------------------------------------------------
/24-react-redux-passing-the-store-down-explicitly-via-props/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/24-react-redux-passing-the-store-down-explicitly-via-props/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { Component } = React;
58 |
59 | const Link = ({
60 | active,
61 | children,
62 | onClick
63 | }) => {
64 | if (active) {
65 | return {children} ;
66 | }
67 |
68 | return (
69 | {
71 | e.preventDefault();
72 | onClick();
73 | }}
74 | >
75 | {children}
76 |
77 | );
78 | };
79 |
80 | class FilterLink extends Component {
81 | componentDidMount() {
82 | const { store } = this.props;
83 | this.unsubscribe = store.subscribe(() =>
84 | this.forceUpdate()
85 | );
86 | }
87 |
88 | componentWillUnmount() {
89 | this.unsubscribe();
90 | }
91 |
92 | render() {
93 | const props = this.props;
94 | const { store } = props;
95 | const state = store.getState();
96 |
97 | return (
98 |
104 | store.dispatch({
105 | type: 'SET_VISIBILITY_FILTER',
106 | filter: props.filter
107 | })
108 | }
109 | >
110 | {props.children}
111 |
112 | );
113 | }
114 | }
115 |
116 | const Footer = ({ store }) => (
117 |
118 | Show:
119 | {' '}
120 |
124 | All
125 |
126 | {', '}
127 |
131 | Active
132 |
133 | {', '}
134 |
138 | Completed
139 |
140 |
141 | );
142 |
143 | const Todo = ({
144 | onClick,
145 | completed,
146 | text
147 | }) => (
148 |
157 | {text}
158 |
159 | );
160 |
161 | const TodoList = ({
162 | todos,
163 | onTodoClick
164 | }) => (
165 |
166 | {todos.map(todo =>
167 | onTodoClick(todo.id)}
171 | />
172 | )}
173 |
174 | );
175 |
176 | let nextTodoId = 0;
177 | const AddTodo = ({ store }) => {
178 | let input;
179 |
180 | return (
181 |
182 | {
183 | input = node;
184 | }} />
185 | {
186 | store.dispatch({
187 | type: 'ADD_TODO',
188 | id: nextTodoId++,
189 | text: input.value
190 | })
191 | input.value = '';
192 | }}>
193 | Add Todo
194 |
195 |
196 | );
197 | };
198 |
199 | const getVisibleTodos = (
200 | todos,
201 | filter
202 | ) => {
203 | switch (filter) {
204 | case 'SHOW_ALL':
205 | return todos;
206 | case 'SHOW_COMPLETED':
207 | return todos.filter(
208 | t => t.completed
209 | );
210 | case 'SHOW_ACTIVE':
211 | return todos.filter(
212 | t => !t.completed
213 | );
214 | }
215 | }
216 |
217 | class VisibleTodoList extends Component {
218 | componentDidMount() {
219 | const { store } = this.props;
220 | this.unsubscribe = store.subscribe(() =>
221 | this.forceUpdate()
222 | );
223 | }
224 |
225 | componentWillUnmount() {
226 | this.unsubscribe();
227 | }
228 |
229 | render() {
230 | const props = this.props;
231 | const { store } = props;
232 | const state = store.getState();
233 |
234 | return (
235 |
243 | store.dispatch({
244 | type: 'TOGGLE_TODO',
245 | id
246 | })
247 | }
248 | />
249 | );
250 | }
251 | }
252 |
253 | const TodoApp = ({ store }) => (
254 |
259 | );
260 |
261 |
262 | const { createStore } = Redux;
263 |
264 | ReactDOM.render(
265 | ,
266 | document.getElementById('root')
267 | );
--------------------------------------------------------------------------------
/25-react-redux-passing-the-store-down-implicitly-via-context/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/25-react-redux-passing-the-store-down-implicitly-via-context/app.css
--------------------------------------------------------------------------------
/25-react-redux-passing-the-store-down-implicitly-via-context/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/25-react-redux-passing-the-store-down-implicitly-via-context/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { Component } = React;
58 |
59 | const Link = ({
60 | active,
61 | children,
62 | onClick
63 | }) => {
64 | if (active) {
65 | return {children} ;
66 | }
67 |
68 | return (
69 | {
71 | e.preventDefault();
72 | onClick();
73 | }}
74 | >
75 | {children}
76 |
77 | );
78 | };
79 |
80 | class FilterLink extends Component {
81 | componentDidMount() {
82 | const { store } = this.context;
83 | this.unsubscribe = store.subscribe(() =>
84 | this.forceUpdate()
85 | );
86 | }
87 |
88 | componentWillUnmount() {
89 | this.unsubscribe();
90 | }
91 |
92 | render() {
93 | const props = this.props;
94 | const { store } = this.context;
95 | const state = store.getState();
96 |
97 | return (
98 |
104 | store.dispatch({
105 | type: 'SET_VISIBILITY_FILTER',
106 | filter: props.filter
107 | })
108 | }
109 | >
110 | {props.children}
111 |
112 | );
113 | }
114 | }
115 | FilterLink.contextTypes = {
116 | store: React.PropTypes
117 | };
118 |
119 | const Footer = () => (
120 |
121 | Show:
122 | {' '}
123 |
126 | All
127 |
128 | {', '}
129 |
132 | Active
133 |
134 | {', '}
135 |
138 | Completed
139 |
140 |
141 | );
142 |
143 | const Todo = ({
144 | onClick,
145 | completed,
146 | text
147 | }) => (
148 |
157 | {text}
158 |
159 | );
160 |
161 | const TodoList = ({
162 | todos,
163 | onTodoClick
164 | }) => (
165 |
166 | {todos.map(todo =>
167 | onTodoClick(todo.id)}
171 | />
172 | )}
173 |
174 | );
175 |
176 | let nextTodoId = 0;
177 | const AddTodo = (props, { store }) => {
178 | let input;
179 |
180 | return (
181 |
182 | {
183 | input = node;
184 | }} />
185 | {
186 | store.dispatch({
187 | type: 'ADD_TODO',
188 | id: nextTodoId++,
189 | text: input.value
190 | })
191 | input.value = '';
192 | }}>
193 | Add Todo
194 |
195 |
196 | );
197 | };
198 | AddTodo.contextTypes = {
199 | store: React.PropTypes
200 | };
201 |
202 | const getVisibleTodos = (
203 | todos,
204 | filter
205 | ) => {
206 | switch (filter) {
207 | case 'SHOW_ALL':
208 | return todos;
209 | case 'SHOW_COMPLETED':
210 | return todos.filter(
211 | t => t.completed
212 | );
213 | case 'SHOW_ACTIVE':
214 | return todos.filter(
215 | t => !t.completed
216 | );
217 | }
218 | }
219 |
220 | class VisibleTodoList extends Component {
221 | componentDidMount() {
222 | const { store } = this.context;
223 | this.unsubscribe = store.subscribe(() =>
224 | this.forceUpdate()
225 | );
226 | }
227 |
228 | componentWillUnmount() {
229 | this.unsubscribe();
230 | }
231 |
232 | render() {
233 | const props = this.props;
234 | const { store } = this.context;
235 | const state = store.getState();
236 |
237 | return (
238 |
246 | store.dispatch({
247 | type: 'TOGGLE_TODO',
248 | id
249 | })
250 | }
251 | />
252 | );
253 | }
254 | }
255 | VisibleTodoList.contextTypes = {
256 | store: React.PropTypes
257 | };
258 |
259 | const TodoApp = () => (
260 |
265 | );
266 |
267 | class Provider extends Component {
268 | getChildContext() {
269 | return {
270 | store: this.props.store
271 | };
272 | }
273 |
274 | render() {
275 | return this.props.children;
276 | }
277 | }
278 | Provider.childContextTypes = {
279 | store: React.PropTypes
280 | };
281 |
282 | const { createStore } = Redux;
283 |
284 | ReactDOM.render(
285 |
286 |
287 | ,
288 | document.getElementById('root')
289 | );
--------------------------------------------------------------------------------
/26-react-redux-passing-the-store-down-with-provider-from-react-redux/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/26-react-redux-passing-the-store-down-with-provider-from-react-redux/app.css
--------------------------------------------------------------------------------
/26-react-redux-passing-the-store-down-with-provider-from-react-redux/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/26-react-redux-passing-the-store-down-with-provider-from-react-redux/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { Component } = React;
58 |
59 | const Link = ({
60 | active,
61 | children,
62 | onClick
63 | }) => {
64 | if (active) {
65 | return {children} ;
66 | }
67 |
68 | return (
69 | {
71 | e.preventDefault();
72 | onClick();
73 | }}
74 | >
75 | {children}
76 |
77 | );
78 | };
79 |
80 | class FilterLink extends Component {
81 | componentDidMount() {
82 | const { store } = this.context;
83 | this.unsubscribe = store.subscribe(() =>
84 | this.forceUpdate()
85 | );
86 | }
87 |
88 | componentWillUnmount() {
89 | this.unsubscribe();
90 | }
91 |
92 | render() {
93 | const props = this.props;
94 | const { store } = this.context;
95 | const state = store.getState();
96 |
97 | return (
98 |
104 | store.dispatch({
105 | type: 'SET_VISIBILITY_FILTER',
106 | filter: props.filter
107 | })
108 | }
109 | >
110 | {props.children}
111 |
112 | );
113 | }
114 | }
115 | FilterLink.contextTypes = {
116 | store: React.PropTypes
117 | };
118 |
119 | const Footer = () => (
120 |
121 | Show:
122 | {' '}
123 |
124 | All
125 |
126 | {', '}
127 |
128 | Active
129 |
130 | {', '}
131 |
132 | Completed
133 |
134 |
135 | );
136 |
137 | const Todo = ({
138 | onClick,
139 | completed,
140 | text
141 | }) => (
142 |
151 | {text}
152 |
153 | );
154 |
155 | const TodoList = ({
156 | todos,
157 | onTodoClick
158 | }) => (
159 |
160 | {todos.map(todo =>
161 | onTodoClick(todo.id)}
165 | />
166 | )}
167 |
168 | );
169 |
170 | let nextTodoId = 0;
171 | const AddTodo = (props, { store }) => {
172 | let input;
173 |
174 | return (
175 |
176 | {
177 | input = node;
178 | }} />
179 | {
180 | store.dispatch({
181 | type: 'ADD_TODO',
182 | id: nextTodoId++,
183 | text: input.value
184 | })
185 | input.value = '';
186 | }}>
187 | Add Todo
188 |
189 |
190 | );
191 | };
192 | AddTodo.contextTypes = {
193 | store: React.PropTypes
194 | };
195 |
196 | const getVisibleTodos = (
197 | todos,
198 | filter
199 | ) => {
200 | switch (filter) {
201 | case 'SHOW_ALL':
202 | return todos;
203 | case 'SHOW_COMPLETED':
204 | return todos.filter(
205 | t => t.completed
206 | );
207 | case 'SHOW_ACTIVE':
208 | return todos.filter(
209 | t => !t.completed
210 | );
211 | }
212 | }
213 |
214 | class VisibleTodoList extends Component {
215 | componentDidMount() {
216 | const { store } = this.context;
217 | this.unsubscribe = store.subscribe(() =>
218 | this.forceUpdate()
219 | );
220 | }
221 |
222 | componentWillUnmount() {
223 | this.unsubscribe();
224 | }
225 |
226 | render() {
227 | const props = this.props;
228 | const { store } = this.context;
229 | const state = store.getState();
230 |
231 | return (
232 |
240 | store.dispatch({
241 | type: 'TOGGLE_TODO',
242 | id
243 | })
244 | }
245 | />
246 | );
247 | }
248 | }
249 | VisibleTodoList.contextTypes = {
250 | store: React.PropTypes
251 | };
252 |
253 | const TodoApp = () => (
254 |
259 | );
260 |
261 | const { Provider } = ReactRedux;
262 | const { createStore } = Redux;
263 |
264 | ReactDOM.render(
265 |
266 |
267 | ,
268 | document.getElementById('root')
269 | );
--------------------------------------------------------------------------------
/27-react-redux-generating-containers-with-connect-from-react-redux-visibletodolist/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/27-react-redux-generating-containers-with-connect-from-react-redux-visibletodolist/app.css
--------------------------------------------------------------------------------
/27-react-redux-generating-containers-with-connect-from-react-redux-visibletodolist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/27-react-redux-generating-containers-with-connect-from-react-redux-visibletodolist/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { Component } = React;
58 |
59 | const Link = ({
60 | active,
61 | children,
62 | onClick
63 | }) => {
64 | if (active) {
65 | return {children} ;
66 | }
67 |
68 | return (
69 | {
71 | e.preventDefault();
72 | onClick();
73 | }}
74 | >
75 | {children}
76 |
77 | );
78 | };
79 |
80 | class FilterLink extends Component {
81 | componentDidMount() {
82 | const { store } = this.context;
83 | this.unsubscribe = store.subscribe(() =>
84 | this.forceUpdate()
85 | );
86 | }
87 |
88 | componentWillUnmount() {
89 | this.unsubscribe();
90 | }
91 |
92 | render() {
93 | const props = this.props;
94 | const { store } = this.context;
95 | const state = store.getState();
96 |
97 | return (
98 |
104 | store.dispatch({
105 | type: 'SET_VISIBILITY_FILTER',
106 | filter: props.filter
107 | })
108 | }
109 | >
110 | {props.children}
111 |
112 | );
113 | }
114 | }
115 | FilterLink.contextTypes = {
116 | store: React.PropTypes
117 | };
118 |
119 | const Footer = () => (
120 |
121 | Show:
122 | {' '}
123 |
124 | All
125 |
126 | {', '}
127 |
128 | Active
129 |
130 | {', '}
131 |
132 | Completed
133 |
134 |
135 | );
136 |
137 | const Todo = ({
138 | onClick,
139 | completed,
140 | text
141 | }) => (
142 |
151 | {text}
152 |
153 | );
154 |
155 | const TodoList = ({
156 | todos,
157 | onTodoClick
158 | }) => (
159 |
160 | {todos.map(todo =>
161 | onTodoClick(todo.id)}
165 | />
166 | )}
167 |
168 | );
169 |
170 | let nextTodoId = 0;
171 | const AddTodo = (props, { store }) => {
172 | let input;
173 |
174 | return (
175 |
176 | {
177 | input = node;
178 | }} />
179 | {
180 | store.dispatch({
181 | type: 'ADD_TODO',
182 | id: nextTodoId++,
183 | text: input.value
184 | })
185 | input.value = '';
186 | }}>
187 | Add Todo
188 |
189 |
190 | );
191 | };
192 | AddTodo.contextTypes = {
193 | store: React.PropTypes
194 | };
195 |
196 | const getVisibleTodos = (
197 | todos,
198 | filter
199 | ) => {
200 | switch (filter) {
201 | case 'SHOW_ALL':
202 | return todos;
203 | case 'SHOW_COMPLETED':
204 | return todos.filter(
205 | t => t.completed
206 | );
207 | case 'SHOW_ACTIVE':
208 | return todos.filter(
209 | t => !t.completed
210 | );
211 | }
212 | }
213 |
214 | const mapStateToProps = (state) => {
215 | return {
216 | todos: getVisibleTodos(
217 | state.todos,
218 | state.visibilityFilter
219 | )
220 | };
221 | };
222 |
223 | const mapDispatchToProps = (dispatch) => {
224 | return {
225 | onTodoClick: (id) => {
226 | dispatch({
227 | type: 'TOGGLE_TODO',
228 | id
229 | });
230 | }
231 | };
232 | };
233 |
234 | const { connect } = ReactRedux;
235 | const VisibleTodoList = connect(
236 | mapStateToProps,
237 | mapDispatchToProps
238 | )(TodoList);
239 |
240 | const TodoApp = () => (
241 |
246 | );
247 |
248 | const { Provider } = ReactRedux;
249 | const { createStore } = Redux;
250 |
251 | ReactDOM.render(
252 |
253 |
254 | ,
255 | document.getElementById('root')
256 | );
--------------------------------------------------------------------------------
/28-react-redux-generating-containers-with-connect-from-react-redux-addtodo/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/28-react-redux-generating-containers-with-connect-from-react-redux-addtodo/app.css
--------------------------------------------------------------------------------
/28-react-redux-generating-containers-with-connect-from-react-redux-addtodo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/28-react-redux-generating-containers-with-connect-from-react-redux-addtodo/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { Component } = React;
58 | const { connect } = ReactRedux;
59 |
60 | const Link = ({
61 | active,
62 | children,
63 | onClick
64 | }) => {
65 | if (active) {
66 | return {children} ;
67 | }
68 |
69 | return (
70 | {
72 | e.preventDefault();
73 | onClick();
74 | }}
75 | >
76 | {children}
77 |
78 | );
79 | };
80 |
81 | class FilterLink extends Component {
82 | componentDidMount() {
83 | const { store } = this.context;
84 | this.unsubscribe = store.subscribe(() =>
85 | this.forceUpdate()
86 | );
87 | }
88 |
89 | componentWillUnmount() {
90 | this.unsubscribe();
91 | }
92 |
93 | render() {
94 | const props = this.props;
95 | const { store } = this.context;
96 | const state = store.getState();
97 |
98 | return (
99 |
105 | store.dispatch({
106 | type: 'SET_VISIBILITY_FILTER',
107 | filter: props.filter
108 | })
109 | }
110 | >
111 | {props.children}
112 |
113 | );
114 | }
115 | }
116 | FilterLink.contextTypes = {
117 | store: React.PropTypes
118 | };
119 |
120 | const Footer = () => (
121 |
122 | Show:
123 | {' '}
124 |
125 | All
126 |
127 | {', '}
128 |
129 | Active
130 |
131 | {', '}
132 |
133 | Completed
134 |
135 |
136 | );
137 |
138 | const Todo = ({
139 | onClick,
140 | completed,
141 | text
142 | }) => (
143 |
152 | {text}
153 |
154 | );
155 |
156 | const TodoList = ({
157 | todos,
158 | onTodoClick
159 | }) => (
160 |
161 | {todos.map(todo =>
162 | onTodoClick(todo.id)}
166 | />
167 | )}
168 |
169 | );
170 |
171 | let nextTodoId = 0;
172 | let AddTodo = ({ dispatch }) => {
173 | let input;
174 |
175 | return (
176 |
177 | {
178 | input = node;
179 | }} />
180 | {
181 | dispatch({
182 | type: 'ADD_TODO',
183 | id: nextTodoId++,
184 | text: input.value
185 | })
186 | input.value = '';
187 | }}>
188 | Add Todo
189 |
190 |
191 | );
192 | };
193 | AddTodo = connect()(AddTodo);
194 |
195 | const getVisibleTodos = (
196 | todos,
197 | filter
198 | ) => {
199 | switch (filter) {
200 | case 'SHOW_ALL':
201 | return todos;
202 | case 'SHOW_COMPLETED':
203 | return todos.filter(
204 | t => t.completed
205 | );
206 | case 'SHOW_ACTIVE':
207 | return todos.filter(
208 | t => !t.completed
209 | );
210 | }
211 | }
212 |
213 | const mapStateToTodoListProps = (
214 | state
215 | ) => {
216 | return {
217 | todos: getVisibleTodos(
218 | state.todos,
219 | state.visibilityFilter
220 | )
221 | };
222 | };
223 | const mapDispatchToTodoListProps = (
224 | dispatch
225 | ) => {
226 | return {
227 | onTodoClick: (id) => {
228 | dispatch({
229 | type: 'TOGGLE_TODO',
230 | id
231 | });
232 | }
233 | };
234 | };
235 | const VisibleTodoList = connect(
236 | mapStateToTodoListProps,
237 | mapDispatchToTodoListProps
238 | )(TodoList);
239 |
240 | const TodoApp = () => (
241 |
246 | );
247 |
248 | const { Provider } = ReactRedux;
249 | const { createStore } = Redux;
250 |
251 | ReactDOM.render(
252 |
253 |
254 | ,
255 | document.getElementById('root')
256 | );
--------------------------------------------------------------------------------
/29-react-redux-generating-containers-with-connect-from-react-redux-footerlink/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/29-react-redux-generating-containers-with-connect-from-react-redux-footerlink/app.css
--------------------------------------------------------------------------------
/29-react-redux-generating-containers-with-connect-from-react-redux-footerlink/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/29-react-redux-generating-containers-with-connect-from-react-redux-footerlink/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | const { Component } = React;
58 | const { connect } = ReactRedux;
59 |
60 | const Link = ({
61 | active,
62 | children,
63 | onClick
64 | }) => {
65 | if (active) {
66 | return {children} ;
67 | }
68 |
69 | return (
70 | {
72 | e.preventDefault();
73 | onClick();
74 | }}
75 | >
76 | {children}
77 |
78 | );
79 | };
80 |
81 | const mapStateToLinkProps = (
82 | state,
83 | ownProps
84 | ) => {
85 | return {
86 | active:
87 | ownProps.filter ===
88 | state.visibilityFilter
89 | };
90 | };
91 | const mapDispatchToLinkProps = (
92 | dispatch,
93 | ownProps
94 | ) => {
95 | return {
96 | onClick: () => {
97 | dispatch({
98 | type: 'SET_VISIBILITY_FILTER',
99 | filter: ownProps.filter
100 | });
101 | }
102 | };
103 | }
104 | const FilterLink = connect(
105 | mapStateToLinkProps,
106 | mapDispatchToLinkProps
107 | )(Link);
108 |
109 | const Footer = () => (
110 |
111 | Show:
112 | {' '}
113 |
114 | All
115 |
116 | {', '}
117 |
118 | Active
119 |
120 | {', '}
121 |
122 | Completed
123 |
124 |
125 | );
126 |
127 | const Todo = ({
128 | onClick,
129 | completed,
130 | text
131 | }) => (
132 |
141 | {text}
142 |
143 | );
144 |
145 | const TodoList = ({
146 | todos,
147 | onTodoClick
148 | }) => (
149 |
150 | {todos.map(todo =>
151 | onTodoClick(todo.id)}
155 | />
156 | )}
157 |
158 | );
159 |
160 | let nextTodoId = 0;
161 | let AddTodo = ({ dispatch }) => {
162 | let input;
163 |
164 | return (
165 |
166 | {
167 | input = node;
168 | }} />
169 | {
170 | dispatch({
171 | type: 'ADD_TODO',
172 | id: nextTodoId++,
173 | text: input.value
174 | })
175 | input.value = '';
176 | }}>
177 | Add Todo
178 |
179 |
180 | );
181 | };
182 | AddTodo = connect()(AddTodo);
183 |
184 | const getVisibleTodos = (
185 | todos,
186 | filter
187 | ) => {
188 | switch (filter) {
189 | case 'SHOW_ALL':
190 | return todos;
191 | case 'SHOW_COMPLETED':
192 | return todos.filter(
193 | t => t.completed
194 | );
195 | case 'SHOW_ACTIVE':
196 | return todos.filter(
197 | t => !t.completed
198 | );
199 | }
200 | }
201 |
202 | const mapStateToTodoListProps = (
203 | state
204 | ) => {
205 | return {
206 | todos: getVisibleTodos(
207 | state.todos,
208 | state.visibilityFilter
209 | )
210 | };
211 | };
212 | const mapDispatchToTodoListProps = (
213 | dispatch
214 | ) => {
215 | return {
216 | onTodoClick: (id) => {
217 | dispatch({
218 | type: 'TOGGLE_TODO',
219 | id
220 | });
221 | }
222 | };
223 | };
224 | const VisibleTodoList = connect(
225 | mapStateToTodoListProps,
226 | mapDispatchToTodoListProps
227 | )(TodoList);
228 |
229 | const TodoApp = () => (
230 |
235 | );
236 |
237 | const { Provider } = ReactRedux;
238 | const { createStore } = Redux;
239 |
240 | ReactDOM.render(
241 |
242 |
243 | ,
244 | document.getElementById('root')
245 | );
--------------------------------------------------------------------------------
/30-react-redux-extracting-action-creators/app.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eggheadio-projects/getting-started-with-redux/4e0c7b99f9b9e1fe8b2bbf5088f712bb4304d18d/30-react-redux-extracting-action-creators/app.css
--------------------------------------------------------------------------------
/30-react-redux-extracting-action-creators/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plunker
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/30-react-redux-extracting-action-creators/script.jsx:
--------------------------------------------------------------------------------
1 | const todo = (state, action) => {
2 | switch (action.type) {
3 | case 'ADD_TODO':
4 | return {
5 | id: action.id,
6 | text: action.text,
7 | completed: false
8 | };
9 | case 'TOGGLE_TODO':
10 | if (state.id !== action.id) {
11 | return state;
12 | }
13 |
14 | return {
15 | ...state,
16 | completed: !state.completed
17 | };
18 | default:
19 | return state;
20 | }
21 | };
22 |
23 | const todos = (state = [], action) => {
24 | switch (action.type) {
25 | case 'ADD_TODO':
26 | return [
27 | ...state,
28 | todo(undefined, action)
29 | ];
30 | case 'TOGGLE_TODO':
31 | return state.map(t =>
32 | todo(t, action)
33 | );
34 | default:
35 | return state;
36 | }
37 | };
38 |
39 | const visibilityFilter = (
40 | state = 'SHOW_ALL',
41 | action
42 | ) => {
43 | switch (action.type) {
44 | case 'SET_VISIBILITY_FILTER':
45 | return action.filter;
46 | default:
47 | return state;
48 | }
49 | };
50 |
51 | const { combineReducers } = Redux;
52 | const todoApp = combineReducers({
53 | todos,
54 | visibilityFilter
55 | });
56 |
57 | let nextTodoId = 0;
58 | const addTodo = (text) => {
59 | return {
60 | type: 'ADD_TODO',
61 | id: nextTodoId++,
62 | text
63 | };
64 | };
65 |
66 | const toggleTodo = (id) => {
67 | return {
68 | type: 'TOGGLE_TODO',
69 | id
70 | };
71 | };
72 |
73 | const setVisibilityFilter = (filter) => {
74 | return {
75 | type: 'SET_VISIBILITY_FILTER',
76 | filter
77 | };
78 | };
79 |
80 | const { Component } = React;
81 | const { Provider, connect } = ReactRedux;
82 |
83 | const Link = ({
84 | active,
85 | children,
86 | onClick
87 | }) => {
88 | if (active) {
89 | return {children} ;
90 | }
91 |
92 | return (
93 | {
95 | e.preventDefault();
96 | onClick();
97 | }}
98 | >
99 | {children}
100 |
101 | );
102 | };
103 |
104 | const mapStateToLinkProps = (
105 | state,
106 | ownProps
107 | ) => {
108 | return {
109 | active:
110 | ownProps.filter ===
111 | state.visibilityFilter
112 | };
113 | };
114 | const mapDispatchToLinkProps = (
115 | dispatch,
116 | ownProps
117 | ) => {
118 | return {
119 | onClick: () => {
120 | dispatch(
121 | setVisibilityFilter(ownProps.filter)
122 | );
123 | }
124 | };
125 | }
126 | const FilterLink = connect(
127 | mapStateToLinkProps,
128 | mapDispatchToLinkProps
129 | )(Link);
130 |
131 | const Footer = () => (
132 |
133 | Show:
134 | {' '}
135 |
136 | All
137 |
138 | {', '}
139 |
140 | Active
141 |
142 | {', '}
143 |
144 | Completed
145 |
146 |
147 | );
148 |
149 | const Todo = ({
150 | onClick,
151 | completed,
152 | text
153 | }) => (
154 |
163 | {text}
164 |
165 | );
166 |
167 | const TodoList = ({
168 | todos,
169 | onTodoClick
170 | }) => (
171 |
172 | {todos.map(todo =>
173 | onTodoClick(todo.id)}
177 | />
178 | )}
179 |
180 | );
181 |
182 | let AddTodo = ({ dispatch }) => {
183 | let input;
184 |
185 | return (
186 |
187 | {
188 | input = node;
189 | }} />
190 | {
191 | dispatch(addTodo(input.value));
192 | input.value = '';
193 | }}>
194 | Add Todo
195 |
196 |
197 | );
198 | };
199 | AddTodo = connect()(AddTodo);
200 |
201 | const getVisibleTodos = (
202 | todos,
203 | filter
204 | ) => {
205 | switch (filter) {
206 | case 'SHOW_ALL':
207 | return todos;
208 | case 'SHOW_COMPLETED':
209 | return todos.filter(
210 | t => t.completed
211 | );
212 | case 'SHOW_ACTIVE':
213 | return todos.filter(
214 | t => !t.completed
215 | );
216 | }
217 | }
218 |
219 | const mapStateToTodoListProps = (
220 | state
221 | ) => {
222 | return {
223 | todos: getVisibleTodos(
224 | state.todos,
225 | state.visibilityFilter
226 | )
227 | };
228 | };
229 | const mapDispatchToTodoListProps = (
230 | dispatch
231 | ) => {
232 | return {
233 | onTodoClick: (id) => {
234 | dispatch(toggleTodo(id));
235 | }
236 | };
237 | };
238 | const VisibleTodoList = connect(
239 | mapStateToTodoListProps,
240 | mapDispatchToTodoListProps
241 | )(TodoList);
242 |
243 | const TodoApp = () => (
244 |
249 | );
250 |
251 | const { createStore } = Redux;
252 |
253 | ReactDOM.render(
254 |
255 |
256 | ,
257 | document.getElementById('root')
258 | );
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Getting Started with Redux
2 | _by Dan Abramov_
3 |
4 | 
5 |
6 | Managing state in an application is critical, and is often done haphazardly. Redux provides a state container for JavaScript applications that will help your applications behave consistently.
7 | Redux is an evolution of the ideas presented by Facebook's Flux, avoiding the complexity found in [Flux](https://egghead.io/articles/gentle-introduction-to-the-react-flux-architecture) by looking to how applications are built with the Elm language.
8 | Redux is useful for React applications, but React is not a requirement!
9 | In this series, we will learn the basics of Redux, so that you can start using it to simplify your applications.
10 | It's highly recommended that you have a quick read of the [Redux documentation](http://redux.js.org/docs/introduction/Motivation.html) alongside or before you watch the series.
11 | There are some amazing [community notes on this course here on Github](https://github.com/tayiorbeii/egghead.io_redux_course_notes.
12 | Once you are finished with this course be sure to check out part 2: [building-react-applications-with-idiomatic-redux](https://egghead.io/courses/building-react-applications-with-idiomatic-redux)
--------------------------------------------------------------------------------