to
Redux
(Without React)
Define what redux is
Describe actions and reducers in redux
Describe methods on the redux store
A plain JavaScript object that must have a key called type and a string value
{
type: "LOGOUT_USER"
}
The action can have any number of additional keys
A function that accepts the state and an action and returns a new state (entire state object)
function rootReducer(state={}, action) {
switch(action.type) {
case "LOGOUT_USER":
return {...state, login: false}
case "LOGIN_USER":
return {...state, login: true}
default:
return state;
}
}
Use the Redux createStore function which accepts the root reducer as a paramter
const store = Redux.createStore(rootReducer);
The only way to change the state is by calling dispatch
const store = Redux.createStore(rootReducer);
store.dispatch({
type: "LOGIN_USER"
});
You can get the state of the Redux store using getState
const store = Redux.createStore(rootReducer);
store.dispatch({
type: "LOGIN_USER"
});
const newState = store.getState();
You can add a listener to see when the state has changed
const store = Redux.createStore(rootReducer);
const changeCallback = () => {
console.log("State has changed",
store.getState());
}
const unsubscribe =
store.listen(changeCallback);
Redux State Change
Describe react-redux
Use the provider component to share a store
Use connect to mapStateToProps and mapDispatchToProps
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import {createStore} from 'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
import React from 'react';
import {connect} from 'react-redux';
const BoldName = ({name}) => (
<strong>{name}</strong>
);
const mapStateToProps = state => (
{ name: state.name }
);
export default
connect(mapStateToProps, null)(BoldName);
import React from 'react';
import {connect} from 'react-redux';
const DelName = ({delName}) => (
<button type="button"
onClick={delName}>DELETE</button>
);
const mapDispatchToProps = (
dispatch, ownProps
) => (
{
delName: () => (dispatch({
type: "DEL_NAME"
}))
}
);
export default
connect(null, mapDispatchToProps)(DelName);
import React from 'react';
import BoldName from './BoldName';
import DelName from './DelName';
const App = () => (
<div>
<BoldName />
<DelName />
</div>
);
Define a presentational component vs a container component
Define combine reducers
Define action creators
Describe a folder structure for redux
import {combineReducers} from 'redux';
import currentUser from './currentUser';
import messages from './messages';
const rootReducer = combineReducers({
currentUser,
messages,
});
export default rootReducer;
combineReducers
const messages = (state=[], action) => {
switch(action.type) {
case "LOAD_MESSAGES":
return [...action.messages];
case "ADD_MESSAGE":
return [action.message, ...state];
default:
return state;
}
};
export default messages;
Messages Reducer
Action Creators
const mapDispatchToProps = dispatch => ({
onLogout() {
dispatch({
type: "USER_LOGOUT"
})
},
});
const mapDispatchToProps = dispatch => ({
onLogout() {
dispatch(actions.userLogout())
},
});
Define redux middleware
Define redux thunk and show a use case
import { createStore,
applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { createLogger } from 'redux-logger'
import reducer from './reducers'
const middleware = [ thunk ]
if (process.env.NODE_ENV !== 'production') {
middleware.push(createLogger())
}
const store = createStore(
reducer,
applyMiddleware(...middleware)
)
export const receivePosts = (reddit, json) => ({
type: RECEIVE_POSTS,
reddit,
posts: json.data.children.map(child => child.data),
receivedAt: Date.now()
}
const fetchPosts = reddit => (
dispatch => {
dispatch(requestPosts(reddit))
return fetch(`https://www.reddit.com/r/${reddit}.json`)
.then(response => response.json())
.then(json => dispatch(receivePosts(reddit, json)))
}
)
Modify the address bar with history.pushState
Describe how bookmarking a single page application works
history.back();
history.forward();
history.pushState({}, 'title', '/newpage');
Server Side Rendering
GET /
index.html (fully rendered)
GET /signin
/signin (fully rendered)
Node.js
HTML
GET /
index.html (only div id="root")
Node.js
React
Render react app
Change address to /signin
Render /signin component
GET /user/55
index.html (only div id="root")
Node.js
React
Render react app with
correct user component
Bookmarked /user/55
Server side support is required
Describe React Router v4
Differentiate BrowserRouter vs HashRouter
Use Link, Switch, and Route components
import React from 'react';
import ReactDOM from 'react-dom';
import {
BrowserRouter as Router
} from 'react-router-dom';
import App from './App';
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById('root')
);
import React, {Component} from 'react';
import {
Switch, Route
} from 'react-router-dom';
const Homepage = () => (<div>HOMEPAGE</div>);
const About = () => (<div>ABOUT</div>);
const SwitchDemo = () => (
<Switch>
<Route path="/about" component={About}/>
<Route path="/" component={Homepage}/>
</Switch>
);
Link
import React from 'react';
import {Link} from 'react-router-dom';
import SwitchDemo from './SwitchDemo';
const App = () => (
<div>
<Link to="/">HOME</Link>
<Link to="/about">ABOUT</Link>
<div style={{fontSize: '3em',
margin: '25px'}}>
<SwitchDemo/>
</div>
</div>
);
NavLink
import React from 'react';
import {NavLink} from 'react-router-dom';
import SwitchDemo from './SwitchDemo';
const s={color: "red"}; //active style
const App = () => (
<div>
<NavLink exact activeStyle={s} to="/">
HOME
</NavLink>
<NavLink exact activeStyle={s} to="/about">
ABOUT
</NavLink>
<div style={{fontSize: '3em',margin: '25px'}}>
<SwitchDemo/>
</div>
</div>
);
Use URL parameters for a Route
Define Route props
Define withRouter
Passing your own props to a component in Route (render vs component)
URL Parameters
import React from 'react';
import {
Switch, Route
} from 'react-router-dom';
const Homepage = () => (<div>HOMEPAGE</div>);
const Name = ({match}) => (
<div>Hello, {match.params.name}</div>
);
const SwitchDemo = () => (
<Switch>
<Route path="/:name" component={Name}/>
<Route path="/" component={Homepage}/>
</Switch>
);
match - info about how the url matches the route component
location - where you are now, similar to window.location
history - similar to html5 history object, allows explicit changes to the url
import {
withRouter, Switch, Route
} from 'react-router-dom';
const SwitchDemo = ({history}) => (
<div>
<Switch>
<Route path="/:name" component={Name}/>
<Route path="/" component={Homepage}/>
</Switch>
<button onClick={() => history.push('/')}>
Go Home
</button>
</div>
);
export default withRouter(SwitchDemo);
import {Route} from 'react-router-dom';
const teachers = ['Tim', 'Colt', 'Matt', 'Elie'];
const Teachers = ({teachers}) => (
<ul>
{teachers.map((teach, ind) => (
<li key={i}>{teach}</li>
))}
</ul>
);
const App = () => (
<Route path="/teachers" render={props => (
<Teachers {...props} teachers={teachers} />
)}/>
);