Преглед изворни кода

Merge branch 'master' of gitlab.com:bebeco/Tutorials

Tomi Cvetic пре 8 година
родитељ
комит
2f62797a80
3 измењених фајлова са 164 додато и 2 уклоњено
  1. 93 0
      LearnRedux/ReduxSagas.md
  2. 41 1
      LearnRedux/Videos.md
  3. 30 1
      ReactForBeginners/Videos.md

+ 93 - 0
LearnRedux/ReduxSagas.md

@@ -0,0 +1,93 @@
+# Using Sagas
+<https://redux-saga.github.io/redux-saga/docs/introduction/BeginnerTutorial.html>
+
+* Sagas connect as middleware to a redux store.
+* Sagas run like cuncurrent worker tasks and have to be started for that.
+
+```jsx
+// main.js
+import { createStore, applyMiddleware } from 'redux'
+import createSagaMiddleware from 'redux-saga'
+
+import { rootSaga } from './sagas'
+
+const sagaMiddleware = createSagaMiddleware()
+const store = createStore(
+  reducer,
+  applyMiddleware(sagaMiddleware)
+)
+sagaMiddleware.run(helloSaga)
+```
+
+* Asynchronous actions need to be split into more tasks to the dispatcher, so reducers can always return immediately:
+
+```jsx
+// actions.js
+function increment(payload) {
+    return {
+        type: 'INCREMENT_REQUEST',
+        payload
+    }
+}
+
+// reducers.js
+export default function counter(state = 0, action) {
+    switch (action.type) {
+        case 'INCREMENT_REQUEST':
+            // disable button
+            // print message
+            /* YOU DON'T NEED TO CALL THE FUNCTION HERE.
+            IT'S INTERCEPTED BY THE MIDDLEWARE. */
+            return state
+        case 'INCREMENT_SUCCESS':
+            return state + 1
+        case 'INCREMENT_FAIL':
+            // print error message
+        default:
+            return state
+    }
+}
+
+// sagas.js
+import { call, put, takeEvery } from 'redux-saga/effects'
+
+// Worker
+export function * incrementAsync () {
+    try {
+        const data = yield call(Api.isIncrementOk)
+        yield put({ type: 'INCREMENT_SUCCESS', data })
+    } catch (error) {
+        yield put({ type: 'INCREMENT_FAIL', error})
+    }
+}
+
+// Watcher (intercepts INCREMENT_REQUEST, dispatches INCREMENT_SUCCESS or INCREMENT_FAIL in return.)
+export function * watchIncrementAsync() {
+    yield takeEvery('INCREMENT_REQUEST', incrementAsync)
+}
+
+// export all sagas in parallel
+export default function * rootSaga() {
+    yield takeEvery('INCREMENT_REQUEST')
+    yield takeEvery('DECREMENT_REQUEST')
+}
+```
+
+## Saga helpers
+* Yield 'effects', in 'redux-saga/effects'
+* `takeEvery` handles every action of a type that is dispatched.
+* Allows multiple `incrementAsync` instances to be started concurrently.
+* `takeLatest` in contrast only takes the response of the latest requested action.
+* Allows only one `incrementAsync` to run at a time
+* If another task is requested, the previous is automatically cancelled.
+* You can start multiple sagas which behave like they were forked.
+
+## Declarative effects
+* Effects are plain JavaScript objects expressing Saga logic.
+* they contain information to be interpreted by the middleware.
+* Sagas can yield effects in multiple forms, the easiest are promises
+* Use `call` to call functions. Call returns on object describing to the middleware what to do. This is similar to action creators, which describe actions for the reducer.
+* For testing, you can just check whether the effect object ist correct, you don't need to actually call the async function.
+    - <https://redux-saga.github.io/redux-saga/docs/basics/DeclarativeEffects.html>
+
+## Dispathing actions to the store

+ 41 - 1
LearnRedux/Videos.md

@@ -254,6 +254,11 @@ render() {
                         text: action.comment,
                     }
                 ]
+            case 'REMOVE_COMMENT':
+                return [
+                    ...state.slice(0, action.index),
+                    ...state.slice(action.index + 1)
+                ]
             default:
                 return state
         }
@@ -270,5 +275,40 @@ render() {
 
     export default comment
     ```
+    
+    - Recall slices, spreads.
+    - Think about what needs to get passed. This makes the code faster.
+
+## Video 18: Hot Reloading Redux Reducers with Webpack
+* Hot reloading only works for components etc. but not for reducer code changes.
+* if you want that, add the following code to store.js
+
+```jsx
+if (module.hot) {
+    module.hot.accept('./reducers/', () => {
+        const nextRootReducer = require('./reducers/index').default
+        store.replaceReducer(nextRootReducer)
+    })
+}
+```
+
+## Video 19: Learning Redux Dev Tools
+* To make use of the Redux dev tools (for chrome), you need to announce your store to the browser:
+
+```jsx
+// index.js
+const enhancers = compose(
+    window.devToolsExtension ? window.devToolsExtension() : f => f
+)
+
+const store = createStore(rootReducer, defaultState, enhancers)
+```
 
-## Video 18: Hot Reloading Redux Reducers with Webpack
+## Video 20: Wrap Up and Next Steps
+* Main idea: One giant store
+* Update it with actions
+* When actions get dispatched, they are handled by reducers
+* expose action creators and store to subcomponents
+* Can't use asynchronous functions in reducers. If you need to, there's Redux thunk and redux sagas.
+* If you have a lot of nested data comming through JSON APIs, look at normalizr
+* Look at existing sites and think about how to implement them in React/Redux.

+ 30 - 1
ReactForBeginners/Videos.md

@@ -322,4 +322,33 @@ const { details } = this.props
 	- leave
 	- appear
 
-## Video 23: Authentication
+## Video 23: Component Validation with PropTypes
+* When sharing components with other people, use PropTypes to declared what needs to be passed to them.
+
+```jsx
+const Header = function() {...}
+Header.propTypes = {
+	tagline: React.PropTypes.string.isRequired
+}
+```
+
+## Video 24: Authentication
+
+## Video 25: Building React for Production
+* If you start with create-react-app, you can use `npm build`
+* creates optimized js and css files in the `build` folder.
+* when you deploy, you need to catch the URL routing and let react-router handle URLs.
+* otherwise, on reloads serving index.html will fail.
+
+## Video 28: Deploying to Apache Server
+* Depending whether you run from the root or a subdirectory, you need to specify `<BrowserRouter basename='/somefolder'>` or not.
+* You also neet to specify this in package.json under "homepage"
+* Put the files on the server
+* in .htaccess define
+```
+RewriteBase /
+RewriteRule ^index\.html$ - [L]
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule . /index.html [L]
+```