Basic Tutorial Flashcards
What are actions?
Actions are plain JavaScript objects or payloads of information that send data from your application to your store.
What is the only source of information for the store?
Actions.
How do you send an action to the store?
By using using store.dispatch().
What must actions have?
A type property that indicates the type of action being performed.
What should types typically be defined as?
String constants.
What is this an example of?
const ADD_TODO = ‘ADD_TODO’
{
type: ADD_TODO,
text: ‘Build my first Redux app’
}
An action which represents adding a new todo item.
What might you want to do once your app is large enough?
Move Actions into a separate module.
It’s a good idea to pass as little data in each action as possible.
For example, it’s better to pass index than the whole todo object.
What are action creators?
Functions that create actions.
Why would you use an action creator to return an action?
To make them portable and easy to test.
What is an example of an action creator?
function addTodo(text) { return { type: ADD_TODO, text } }
How would you initiate a dispatch in Redux?
Pass the result to the dispatch() function, or create a bound action creator that automatically dispatches.
Give a simple example of passing a result to a dispatch() function.
dispatch(addTodo(text))
dispatch(completeTodo(index))
Give a simple example of how you would create a bound action creator that automatically dispatches.
const boundAddTodo = text => dispatch(addTodo(text)) const boundCompleteTodo = index => dispatch(completeTodo(index))
What is the advantage of using a bound action creator that automatically dispatches?
You can call them directly.
Give a simple example of how you would directly call a bound action creator that automatically dispatches.
boundAddTodo(text)
boundCompleteTodo(index)
How would you directly access the the dispatch() function from the store?
by using store.dispatch() or more likely by accessing it using a helper like react-redux’s connect().
How would you automatically bind many action creators to a dispatch() function?
By using bindActionCreators()
What do reducers do?
They specify how the application’s state changes in response to actions sent to the store.
How do actions differ from reducers?
Actions only describe what happened, but don’t describe how the application’s state changes.
How is all the applications state stored?
In a single object.
What is a good practice before creating an apps state?
To figure out the minimal representation of your app’s state as an object.
what should you do if you need to store some data, as well as some UI state, in the state tree?
Try to keep them separate.
What’s a best practice when creating an apps state?
To keep it as normalized as possible, without any nesting and to keep every entity in an object stored with an ID as a key, and use IDs to reference it from other entities, or lists.
What is a reducer?
A pure function that takes the previous state and an action, and returns the next state.
Give an example of a reducer.
(previousState, action) => nextState
Why is it called a reducer?
Because it’s the type of function you would pass to Array.prototype.reduce(reducer, ?initialValue).
What should you never do in a reducer?
Mutate its arguments
Perform side effects like API calls and routing transitions
Call non-pure functions, e.g. Date.now() or Math.random()
What should a reducer do?
Given the same arguments, it should calculate the next state and return it. No surprises. No side effects. No API calls. No mutations. Just a calculation.
What will Redux do the first time?
Call our reducer with an undefined state
When Redux calls our reducer for the first time, what is this a good opportunity to do?
To return the initial state of our app.
Convert this code to take advantage of ES6
default argument syntax:
import { VisibilityFilters } from './actions' const initialState = { visibilityFilter: VisibilityFilters.SHOW_ALL, todos: [] } function todoApp(state, action) { if (typeof state === 'undefined') { return initialState } // For now, don't handle any actions // and just return the state given to us. return state }
import { VisibilityFilters } from './actions' const initialState = { visibilityFilter: VisibilityFilters.SHOW_ALL, todos: [] } function todoApp(state = initialState, action) { // For now, don't handle any actions // and just return the state given to us. return state }
What do you notice with this code?
import { SET_VISIBILITY_FILTER, VisibilityFilters } from './actions' ... function todoApp(state = initialState, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return Object.assign({}, state, { visibilityFilter: action.filter }) default: return state } }
We don’t mutate the state. We create a copy with Object.assign().
NOTE:
Object.assign(state, { visibilityFilter: action.filter }) is also wrong: it will mutate the first argument. You must supply an empty object as the first parameter.
We return the previous state in the default case. It’s important to return the previous state for any unknown action.
What is noteworthy about Object.assign?
It’s part of ES6, and is not supported by older browsers. To support them, you will need to either use a polyfill, a Babel plugin, or a helper from another library like _.assign().
How would you update a specific item in an array without resorting to mutations?
Create a new array with the same items except the item at the index.
If you find yourself often wanting to update a specific item in an array without resorting to mutations, what is it a good idea to do?
Use a helper like immutability-helper, updeep, or even a library like Immutable that has native support for deep updates.
When is the only time you can assign to anything inside the state?
When you clone it first.
What do you notice here?
function todos(state = [], action) { switch (action.type) { case ADD_TODO: return [ ...state, { text: action.text, completed: false } ] case TOGGLE_TODO: return state.map((todo, index) => { if (index === action.index) { return Object.assign({}, todo, { completed: !todo.completed }) } return todo }) default: return state } } function todoApp(state = initialState, action) { switch (action.type) { case SET_VISIBILITY_FILTER: return Object.assign({}, state, { visibilityFilter: action.filter }) case ADD_TODO: return Object.assign({}, state, { todos: todos(state.todos, action) }) case TOGGLE_TODO: return Object.assign({}, state, { todos: todos(state.todos, action) }) default: return state } }
todos also accepts state—but state is an array! Now todoApp gives todos just a slice of the state to manage, and todos knows how to update just that slice. This is called reducer composition, and it’s the fundamental pattern of building Redux apps.
reducer1
qw
reducer2
qw
reducer3
sd
reducer4
reducer5
11
reducer6
reducer7
reducer8
reducer9
reducer10
reducer11
reducer12
reducer13
reducer14
reducer15
What is the store?
It’s an object that brings actions and reducers together.
What is the stores responsibilities?
Holds application state;
Allows access to state via getState();
Allows state to be updated via dispatch(action);
Registers listeners via subscribe(listener);
Handles unregistering of listeners via the function returned by subscribe(listener).
How many stores will you have in a Redux application?
One.
What would you do if you want to split your data handling logic?
Use reducer composition.
How would you create a store from a reducer?
import { createStore } from 'redux' import todoApp from './reducers' const store = createStore(todoApp)
What may you do as the second argument to createStore()?
Specify the initial state.
Why is it useful to optionally specify the initial state as the second argument to createStore()?
For hydrating the state of the client to match the state of a Redux application running on the server.
Give an example of using the second argument to createStore().
const store = createStore(todoApp, window.STATE_FROM_SERVER)
What does the Redux architecture revolve around?
A strict unidirectional data flow.
What does it mean when the Redux architecture is said to revolve around a strict unidirectional data flow?
all data in an application follows the same lifecycle pattern, making the logic of your app more predictable and easier to understand.
What does the Redux architecture revolving around a strict unidirectional data flow encourage and why is it desirable?
Data normalization, so that you don’t end up with multiple, independent copies of the same data that are unaware of one another.
What are the data lifecycle steps in any Redux app?
You call store.dispatch(action)
The Redux store calls the reducer function you gave it.
The root reducer may combine the output of multiple reducers into a single state tree.
The Redux store saves the complete state tree returned by the root reducer.
What is this an example of?
{ type: ‘LIKE_ARTICLE’, articleId: 42 }
{ type: ‘FETCH_USER_SUCCESS’, response: { id: 3, name: ‘Mary’ } }
{ type: ‘ADD_TODO’, text: ‘Read the Redux docs.’ }
An action.
What’s a good way of thinking about Actions? Give some examples.
As a very brief snippet of news.
“Mary liked article 42.” or “’Read the Redux docs.’ was added to the list of todos.”
Where can you call store.dispatch(action)?
From anywhere in your app, including components and XHR callbacks, or even at scheduled intervals.
What arguments will the store pass to the reducer?
The current state tree and the action.
What is this an example of?
// The current application state (list of todos and chosen filter) let previousState = { visibleTodoFilter: 'SHOW_ALL', todos: [ { text: 'Read the docs.', complete: false } ] } // The action being performed (adding a todo) let action = { type: 'ADD_TODO', text: 'Understand the flow.' } // Your reducer returns the next application state let nextState = todoApp(previousState, action)
Something the root reducer might receive.
When should you perform any side effects like API calls or router transitions.
Before an action is dispatched.
What is the combineReducers() helper function useful for?
“splitting” the root reducer into separate functions that each manage one branch of the state tree.
Give and example of how combineReducers() work?
Let’s say you have two reducers, one for a list of todos, and another for the currently selected filter setting. When you emit an action, todoApp returned by combineReducers will call both reducers. It will then combine both sets of results into a single state tree.
Give and example of how combineReducers() work using two reducers, one for a list of todos, and another for the currently selected filter setting.
function todos(state = [], action) { // Somehow calculate it... return nextState } function visibleTodoFilter(state = 'SHOW_ALL', action) { // Somehow calculate it... return nextState } let todoApp = combineReducers({ todos, visibleTodoFilter })
When you emit an action, todoApp returned by combineReducers will call both reducers.
let nextTodos = todos(state.todos, action) let nextVisibleTodoFilter = visibleTodoFilter(state.visibleTodoFilter, action)
It will then combine both sets of results into a single state tree:
return {
todos: nextTodos,
visibleTodoFilter: nextVisibleTodoFilter
}
What happens when the Redux store saves the complete state tree returned by the root reducer.
This new tree is now the next state of your app.
When the Redux store saves the complete state tree returned by the root reducer, what happens to every listener registered with store.subscribe(listener).
They will now be invoked.
Bottom of Data Flow
11
Bottom of Data Flow2
11
Why does Redux work especially well with libraries like React and Deku?
Because they let you describe UI as a function of state, and Redux emits state updates in response to actions.
React bindings are not included in Redux by default. How would you install them explicitly?
npm install –save react-redux
What is the function of React bindings for Redux?
To separate presentational components from container components.
Why is it a good idea to separate presentational components from container components?
Can make your app easier to understand and allow you to more easily reuse components.
What is the purpose of presentational components?
To define how things look (markup, styles).
What is the purpose of container components?
To define how things work (data fetching, state updates).
Are presentational components aware of Redux?
No.
Are container components aware of Redux?
Yes.
How does presentational components read data?
From props.
How does container components read data?
By subscribing to Redux state.
How does presentational components change data?
By invoking callbacks from props.
How does container components change data?
By dispatching Redux actions.
How are presentational components written?
Manually.
How are container components written?
Usually generated by React Redux.
What should you do if a container component becomes too complex (i.e. it has heavily nested presentational components with countless callbacks being passed down)?
Introduce another container within the component tree.
Why shouldn’t you write the container components by hand using store.subscribe()?
Because React Redux makes many performance optimizations that are hard to do by hand. For this reason, rather than write container components, we will generate them using the connect() function provided by React Redux.
What should you do if it’s hard to tell if some component should be a presentational component or a container?
Just mix the presentation and logic in a component. As it grows, it will be more obvious how to split it.
What is a container component?
It’s just a React component that uses store.subscribe() to read a part of the Redux state tree and supply props to a presentational component it renders.
What is a better practice than writing a container component by hand?
Generating container components with the React Redux library’s connect() function.
Why is it a better practice to generate container components with the React Redux library’s connect() function than writing a container component by hand?
It provides many useful optimizations to prevent unnecessary re-renders. (One result of this is that you shouldn’t have to worry about the React performance suggestion of implementing shouldComponentUpdate yourself.)
How would you use connect()
Define a special function called mapStateToProps that describes how to transform the current Redux store state into the props you want to pass to a presentational component you are wrapping.
What can container components do apart from reading the state?
Dispatch actions.
What is the user defined function called mapDispatchToProps() used for?
To receive the dispatch() method and return callback props that you want to inject into the presentational component.
Define a function that filters the state.todos according to the state.visibilityFilter, and use it in its mapStateToProps.
const getVisibleTodos = (todos, filter) => { switch (filter) { case 'SHOW_COMPLETED': return todos.filter(t => t.completed) case 'SHOW_ACTIVE': return todos.filter(t => !t.completed) case 'SHOW_ALL': default: return todos } } const mapStateToProps = state => { return { todos: getVisibleTodos(state.todos, state.visibilityFilter) } }
Create a function where VisibleTodoList injects a prop called onTodoClick into the TodoList component, and for onTodoClick to dispatch a TOGGLE_TODO action.
const mapDispatchToProps = dispatch => { return { onTodoClick: id => { dispatch(toggleTodo(id)) } } }
Create VisibleTodoList by calling connect() and passing these two functions: mapStateToProps and mapDispatchToProps.
import { connect } from 'react-redux' const VisibleTodoList = connect( mapStateToProps, mapDispatchToProps )(TodoList) export default VisibleTodoList
Why do all container components need access to the Redux store?
So they can subscribe to it.
Why wouldn’t you pass the store as a prop to every container component?
Because it gets tedious, as you have to wire store even through presentational components just because they happen to render a container deep in the component tree.
Whats a better option than passing the store as a prop to every container component?
Use a special React Redux component called < Provider > to magically make the store available to all container components in the application without passing it explicitly.
How many times do you need to use < Provider >?
Once.
When do you need to use < Provider >?
when you render the root component.