|
@@ -7,6 +7,7 @@
|
|
|
## Video 3: Create Single and PhotoGrid components
|
|
|
|
|
|
## Video 4: Setting up React Router
|
|
|
+
|
|
|
```javascript
|
|
|
import { Router, Route, IndexRoute, browserHistory } from 'react-router'
|
|
|
|
|
@@ -21,12 +22,14 @@ const router = (
|
|
|
|
|
|
render(router, document.getElementById('root'))
|
|
|
```
|
|
|
+
|
|
|
* Use `<Link to=''>Bla</Link>` to create push state links.
|
|
|
* browserHistory will be replaced later by `history` which first syncs the browser history with the react store (see next video).
|
|
|
|
|
|
## Video 5: Setting up React Store
|
|
|
* One giant state for all data
|
|
|
* it is called `store`
|
|
|
+
|
|
|
```javascript
|
|
|
import { createStore, compose } from 'redux'
|
|
|
import { syncHistoryWithStore } from 'react-router-redux'
|
|
@@ -43,6 +46,7 @@ export default store
|
|
|
* actions invoke changes of the state (adding, updating, removing data)
|
|
|
* actions are objects with two elements: type and payload
|
|
|
* action creators are functions which return actions:
|
|
|
+
|
|
|
```javascript
|
|
|
function increment(index) {
|
|
|
return {
|
|
@@ -68,6 +72,7 @@ function addComment(postId, author, comment) {
|
|
|
- a copy of the current state
|
|
|
* reducers return the updated state if there is a change, or the previous state
|
|
|
* always start like this and then add some conditional functionality:
|
|
|
+
|
|
|
```javascript
|
|
|
function posts(state = [], action) {
|
|
|
if (...) {
|
|
@@ -78,7 +83,9 @@ function posts(state = [], action) {
|
|
|
|
|
|
export default posts
|
|
|
```
|
|
|
+
|
|
|
* combine them in a root reducer
|
|
|
+
|
|
|
```javascript
|
|
|
import { combineReducers } from 'redux'
|
|
|
import { routerReducer } from 'react-router-redux'
|
|
@@ -87,6 +94,7 @@ import posts from './posts'
|
|
|
const rootReducer = combineReducers({ posts, ..., routing: routerReducer })
|
|
|
export default rootReducer
|
|
|
```
|
|
|
+
|
|
|
* always add `routing: routerReducer` at the end to integrate the route changes with other action changes.
|
|
|
* executes URL changes implicitely
|
|
|
* <https://github.com/reactjs/react-router-redux>
|
|
@@ -94,25 +102,25 @@ export default rootReducer
|
|
|
## Video 8: Integrating our Store with React Router
|
|
|
* to make the store globally available, put it on top of the routing
|
|
|
* replace the browserHistory as mentioned before.
|
|
|
-```diff
|
|
|
-import { Router, Route, IndexRoute, browserHistory } from 'react-router'
|
|
|
-+import { Provider } from 'react-redux'
|
|
|
-+import store, { history } from './store'
|
|
|
-
|
|
|
-const router = (
|
|
|
-+ <Provider store={store}>
|
|
|
-- <Router history={browserHistory}>
|
|
|
-+ <Router history={history}>
|
|
|
- <Route path='/' component={Main}>
|
|
|
- <IndexRoute component={} \/>
|
|
|
- <Route path='/view/:postId' \/>
|
|
|
- <\/Route>
|
|
|
- <\/Router>
|
|
|
-+ </Provider>
|
|
|
-)
|
|
|
-
|
|
|
-render(router, document.getElementById('root'))
|
|
|
-```
|
|
|
+ ```diff
|
|
|
+ import { Router, Route, IndexRoute, browserHistory } from 'react-router'
|
|
|
+ +import { Provider } from 'react-redux'
|
|
|
+ +import store, { history } from './store'
|
|
|
+
|
|
|
+ const router = (
|
|
|
+ + <Provider store={store}>
|
|
|
+ - <Router history={browserHistory}>
|
|
|
+ + <Router history={history}>
|
|
|
+ <Route path='/' component={Main}>
|
|
|
+ <IndexRoute component={} \/>
|
|
|
+ <Route path='/view/:postId' \/>
|
|
|
+ <\/Route>
|
|
|
+ <\/Router>
|
|
|
+ + </Provider>
|
|
|
+ )
|
|
|
+
|
|
|
+ render(router, document.getElementById('root'))
|
|
|
+ ```
|
|
|
* The state is now stored in the store. `$r.store.getState()`
|
|
|
|
|
|
## Video 9: Understanding the Reducer's Job and Dispatching Actions
|
|
@@ -120,10 +128,10 @@ render(router, document.getElementById('root'))
|
|
|
* actions invoke state changes
|
|
|
* reducers change the state
|
|
|
* the store provides a dispatch function
|
|
|
-```javascript
|
|
|
-// on the console
|
|
|
-$r.store.dispatch({type: 'INCREMENT', index: 1})
|
|
|
-```
|
|
|
+ ```javascript
|
|
|
+ // on the console
|
|
|
+ $r.store.dispatch({type: 'INCREMENT', index: 1})
|
|
|
+ ```
|
|
|
* The dispatcher sends the action to **every** reducer
|
|
|
* Therefore, the reducer needs to have some conditional logic.
|
|
|
|
|
@@ -131,26 +139,26 @@ $r.store.dispatch({type: 'INCREMENT', index: 1})
|
|
|
* in regular React, the state or parts of it are propagated via props
|
|
|
* in Redux, `connect` injects the data in the components that need it
|
|
|
* for that, we wrap the main component with one that has the state and dispatcher propagated
|
|
|
-```javascript
|
|
|
-import { bindActionCreators } from 'redux'
|
|
|
-import { connect } from 'react-redux'
|
|
|
-import * as actionCreators from './actions/actionCreators'
|
|
|
-import Main from './Main'
|
|
|
-
|
|
|
-function mapStateToProps(state) {
|
|
|
- return {
|
|
|
- posts: state.posts,
|
|
|
- comments: state.comments,
|
|
|
+ ```javascript
|
|
|
+ import { bindActionCreators } from 'redux'
|
|
|
+ import { connect } from 'react-redux'
|
|
|
+ import * as actionCreators from './actions/actionCreators'
|
|
|
+ import Main from './Main'
|
|
|
+
|
|
|
+ function mapStateToProps(state) {
|
|
|
+ return {
|
|
|
+ posts: state.posts,
|
|
|
+ comments: state.comments,
|
|
|
+ }
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-function mapDispatchToProps(dispatch) {
|
|
|
- return bindActionCreators(actionCreators, dispatch)
|
|
|
-}
|
|
|
+ function mapDispatchToProps(dispatch) {
|
|
|
+ return bindActionCreators(actionCreators, dispatch)
|
|
|
+ }
|
|
|
|
|
|
-const App = connect(mapStateToProps, mapDispatchToProps)(Main)
|
|
|
-export default App
|
|
|
-```
|
|
|
+ const App = connect(mapStateToProps, mapDispatchToProps)(Main)
|
|
|
+ export default App
|
|
|
+ ```
|
|
|
* because Main ist just JSX, connect injects standardized props into it and makes the state and dispatcher available.
|
|
|
* You can still propagate data down with props
|
|
|
|
|
@@ -160,39 +168,42 @@ export default App
|
|
|
## Video 12: Updating State with Reducers
|
|
|
* Once you propagate the reducer function to the component, this is how you pass arguments to the function call
|
|
|
- Remember that `<button onClick={this.props.function(argument)} ...>` would call the function at document load!
|
|
|
-```javascript
|
|
|
-<button onClick={this.props.function.bind(null, argument)} ...>
|
|
|
-```
|
|
|
+ ```javascript
|
|
|
+ <button onClick={this.props.function.bind(null, argument)} ...>
|
|
|
+ ```
|
|
|
+
|
|
|
* Use pure functions to manipulate state. So the same inputs (previous state, action) always gives the same output (next state).
|
|
|
- Makes testing easier.
|
|
|
- Enables Redux dev tools, time travel etc.
|
|
|
* Do the same as in React state handling: Copy, modify, return copy:
|
|
|
-```javascript
|
|
|
-function posts(state = [], action) {
|
|
|
- switch(action.type) {
|
|
|
- const i = action.index
|
|
|
- case 'INCREMENT_LIKES' :
|
|
|
- return [
|
|
|
- ...state.slice(0, i),
|
|
|
- { ...state[i], likes: state[i].likes + 1 },
|
|
|
- ...state.slice(i + 1)
|
|
|
- ]
|
|
|
- default:
|
|
|
- return state
|
|
|
+ ```javascript
|
|
|
+ function posts(state = [], action) {
|
|
|
+ switch(action.type) {
|
|
|
+ const i = action.index
|
|
|
+ case 'INCREMENT_LIKES' :
|
|
|
+ return [
|
|
|
+ ...state.slice(0, i),
|
|
|
+ { ...state[i], likes: state[i].likes + 1 },
|
|
|
+ ...state.slice(i + 1)
|
|
|
+ ]
|
|
|
+ default:
|
|
|
+ return state
|
|
|
+ }
|
|
|
}
|
|
|
-}
|
|
|
-```
|
|
|
+ ```
|
|
|
|
|
|
## Video 13: Displaying the Single Photo Component
|
|
|
* Polyfills are new ES6 functions cross compiled for old browsers through Babel. [Example for findIndex()][1]
|
|
|
* You can use `findIndex()` to get a certain element of an array
|
|
|
-```javascript
|
|
|
-render () {
|
|
|
- const i = this.props.posts.findIndex((post) => post.code === this.props.params.postId)
|
|
|
- const post = this.props.posts[i]
|
|
|
- ...
|
|
|
-}
|
|
|
-```
|
|
|
+ ```javascript
|
|
|
+ render () {
|
|
|
+ const { postId } = this.props.params
|
|
|
+ const i = this.props.posts.findIndex((post) => post.code === postId)
|
|
|
+ const post = this.props.posts[i]
|
|
|
+ const comments = this.props.comments[postId] || []
|
|
|
+ ...
|
|
|
+ }
|
|
|
+ ```
|
|
|
[1](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex#Polyfill)
|
|
|
|
|
|
## Video 14: Displaying and Adding Comments
|