Study logs and projects following React and Redux course by Stephen Grider on Udemy
describe
: group together similar tests, params: description and a function containing testsit
: to test a single attribute of a targetexpect
: to make a single assertion about a targetbeforeEach
: for common setup of all test cases inside adescribe
block
- What do we care of how this component works?
- What features we need to make sure work correctly?
- Expect child element using className:
expect(component.find('.class-name')).to.exist;
- Test controlled input component with event simulation:
component.find('textarea').simulate('change', 'new comment');
- Pass state and props to testing component with
renderComponent
function
- Test action creator
- Test reducers - TDD comments reducer
- Test initial case first
- Test each possible actions that the reducer cares about
- Something to run the test
- Loads test, runs them one by one, clean up after each, report errors
- Eg. Mocha
- Something to write test
- Write assertion for certain properties of the test subject
- eg. Chai
- Setup testing environment to run like-a browser in the command line
- Build
renderComponent
helper that render given React component - Build helpers for simulating events
- Setup
chai-jquery
for testing DOM element
- HOC is a function that take in a component and returns a new component with advanced/inhanced features or for other purposes, mainly to reuse component logic
- Eg.
connect
andProvider
inreact-redux
- Component to show protected resources +
require_auth
HOC = Composed component that will check user authentication before rendering - Redux review:
- User click sign in button
- Call the
authenticate
action creator -> return an action (with type=CHANGE_AUTH
and payload=true
) - Action will go to the Authentication Reducer -> return new state (what the payload is,
true
orfalse
) - Application state is updated by reducer
- New state flows into app -> re-render
- Context:
- Similar to props, but spans the entire tree
- Can access
context
without passing through levels - Can be easily abused and be very careful when using
- The child can only access
context
after declaringcontextTypes
as a class-level property/variable (usestatic
)
- Sits between action creators and reducers -> intercepts any action
- Once actions flow into middleware, the middleware can choose to stop/log/modify/.../do anything with actions
- Simple app to display list of users
- App Building Process:
- Build app with dummy data
- Replace dummy data with AJAX
- Write middleware to help fetch data
- Middleware to wait for promise to resolve then send an action to reducers
- Can have multiple middlewares to process the action
next
keyword- Multiple middlewares working with Redux:
const createStoreWithMiddleware = applyMiddleware(Middleware1, Middleware2, MiddlewareN)(createStore);
/**
* Middleware always have the same signature:
* - Take in `dispatch` function
* - Return a function (take in `next`)
* - That function returns another function (take in `action`) that do actual works
* - Send `action` to reducers or next middlewares
*
*/
export default function({ dispatch }) {
return next => action => {
// actual work for this middleware, eg. log the action
console.log(action);
// send the action to the next middleware in the middlewares stack
next(action);
// or send the new action to all the middleware again
dispatch(action);
};
}
- Why
dispatch
overnext
for modifiedaction
:- Once
action
is modified, it should go over all the middlewares once again - There might be some middlewares that need to process with all
action
, if a later middleware modifies theaction
and we callnext
, the previous middlewares will be skipped - Also, to make sure the middlewares stack works without any assumption about the order of middlewares
- Once
morgan
: Express logging middlewarebody-parser
: parse incoming requestsnodemon
: file watcher for updating and reloading server for modified codes
- Setup model schema with
mongoose.Schema
- Setup mongodb and connect node app with database with
mongoose.connect()
- Using
passport
andpassport-jwt
packages passport
- authentication for Node- Passport works with multiple different strategies
- Auth-related application state
{
auth: {
authenticated: BOOLEAN, // change when user signin/signout/signup
error: STRING // change when auth-related error occurs
}
}
- Setup some needed components, eg. react router
- Scaffolding the signin form with
redux-form
- Wire up
redux-form
with React form component:reduxForm({ form: 'signin', fields: ['email', 'password'] }, mapStateToProps, actions)(Signin)
reduxForm
helper works similar toreact-redux
.connect
method: take inmapStateToProps
method andactions
- Use helper function from
redux-form
to submit the form:handleSubmit(callback)
redux-thunk
:- A middleware that helps with access to redux
dispatch
method - Allow returning a function from action creators instead of an action
- That function is automatically called with
dispatch
method
- A middleware that helps with access to redux
- Review: action creator -> return object with type & payload
- Use
cors
npm package
youtube-api-search
npm package for youtube search- Controlled Component
- Downward Data Flow
- ES6 syntax:
{videos: videos}
==={videos}
- Callback for selecting videos: passing from
App
toVideoList
then pass toVideoListItem
as prop - Utility library
lodash
: using_.debounce()
for throttling search term input change
Project dir: redux-book-list
- A function that return a piece of application state
// application state { books: [/*book value*/], // -> Books Reducer activeBook: {/*active book value*/} //-> ActiveBook Reducer }
- Implement:
- Create a reducer
- Wire it up to the application by using a container component
- Reducer gets 2 arguments: current
state
(only the state that reducer is responsible for) andaction
- A component that has direct connection with Redux state
react-redux
: bridge betweenreact
andredux
- Choose component to be container: the most parent component that cares about that particular piece of application state
- Using
connect
: takes a function and a component then produces a container - Whenever state changes:
- The container will auto re-render
- The returned object from
mapStateToProps(state)
function will be assigned asprops
to the component
- Action Creator is a function that returns an action object, is called by some client event (user click, ajax load completion)
- Action has
type
and optional action data{ type: BOOK_SELECTED, book: { title: 'Book 1' } }
- Action is auto sent to all reducers
- The reducer that cares about that action will use the switch to check for it's according
action.type
and useaction
data (payload
) to update the according piece of state - Application state is updated -> all containers are notified of the changes -> containers will re-render with new
props
- Redux app state is a single plain JS object, completely different from Component state
- App state is formed by reducers, all combined by
combineReducers
functions - Reducer uses action to manipulate/ change app state. Whenever an action is dispatched, it flows through all reducers. Then each reducer has the option to return different piece of state based on type of action that it receives
- Action must always have
type
and optional data (payload
, etc.)
*Project dir: redux-middleware-weatherapp
this.someEventCallback = this.someEventCallback.bind(this);
bind the context of this component to it's function so thethis
keyword in that function will always refer to this component.
- A function that takes in action and depending on the action type, payload, etc, it can choose to let the action pass through, manipulate action, log it or stop it >> gate keeper of reducers
- Middleware sits between action creator and reducer
- Why middleware?
- Middleware
redux-promise
:- When receive the action -> check if it has a
promise
as a payload - If yes -> stop the action -> after promise resolves, create new action and send to reducers
- When receive the action -> check if it has a
- Don't mutate the state
- Ensure that always return new instance of state
4. Chart Component with react-sparklines
- Create reusable compoent for chart to avoid repeating code
- Only need functional stateless component to render chart from data
ref
system: allows to have direct reference to a HTML element that has been rendered to the page- After render
<div ref="divName" />
in the component, thediv
can be refered bythis.refs.divName
anywhere in the same component
- After render
componentDidMount()
: a life cycle method that is called right after the element is rendered- Using Google Map:
new google.maps.Map(targetHTMLElement, { //config of map zoon: 12, center: { lat: 0, lng: 0 } });
- Action creator
fetchWeather
using constant foraction.type
- Use of middleware
redux-promise
: detect the payload passed as promise to resolve promise and return new action - Avoid mutating state directly, create and return new object to take a place of existing state
- Destructuring array in ES6
react-sparklines
for chart- Make use of
react-google-maps
element
Project: simple-blog
- API: All requests are based on this API Reference
- Install react router:
npm install --save [email protected]
-
Overall flow:
- User changes URL > signal
History
module History
module parses the change and tellreact-router
the new URLreact-router
updates the react components based on the URLreact-router
tellReact
the components need renderReact
render new content to view
- User changes URL > signal
-
Basic implementation
BrowerRouter
interacts withHistory
library and decide exactly what to do based on the change in URLRoute
provides config toreact-router
- Syntax:
<Route path="/route_url" component={RouteComponent} />
Switch
contains collection ofRoute
and render the first matchedRoute
Link
component fromreact-router-dom
for an anchor tag- Redirect between route:
this.props.history.push('/route/here');
- Access params of route:
this.props.match.params.paramName
- Create
/
route withPostsIndex
component andPostsReducer
to show list of posts - New Post form:
- Scaffold
PostsNew
component - Add route config
- Add navigation between index & new
- Add form to
PostsNew
- Make action creator to save a post
- Scaffold
4. Using redux-form
for rich function form
-
Make sure to hookup form reducer from
redux-form
to the keyform
incombineReducers()
function -
Flow:
- Identify different pieces of form state
- Make
Field
component for each piece of state - User changes a
Field
input redux-form
auto handle changes- User submits form
- Validate inputs & handle form submission (by callback)
-
Modules:
Field
only know how to interact with Redux Form without display itself, socomponent
property help to return some JSX to render the FieldreduxForm
helper function (similar toconnect
fromreact-redux
) -> allows our components to communicate with form reducer<input {...field.input} />
: pass all event handlers from redux form to an input element
-
Form validation
- Use a helper function
validate()
that is auto called by redux form once the user submits form - Return an errors object, if
errors === null
, the form is valid - Use
field.meta.error
to access the error object fromerror.fieldName
to display error message for field withname="fieldName"
- States of the redux form: pristine, touched, invalid
- Use a helper function
-
Submit form
- Redux Form only cares about state of the form, doesn't help posting form to backend
-
Use destructuring to access property from nested object:
const { meta: { touched, error } } = field;
means:- Get
touch
anderror
fromfield.meta
and assign them totouch
&error
variables accordingly
- Get
-
POST form data to server
- Use a
createPost
action creator: user submit->validate form->callonSubmit
->call action creator to make API request->after success, navigate to post list OPTIONS
Request Method is used when making cross-origin request (CORS - Cross-Origin Resource Sharing)
- Use a
-
ES6 syntax
- Key interpolation
{ ...currentObject }
return a new object that is same with currentObject
-
function mapStateToProps({ posts }, ownProps)
->ownProps
is the props that going to the target component