Redux notes that might get deleted from OUR gist
https://frontend.turing.io/lessons/module-3/ideabox-to-redux.html https://frontend.turing.io/lessons/module-3/react-to-redux-workshop.html
Set Up
git clone https://github.com/filepath.git rename-if-you-want
cd rename-if-you-want
npm i
npm start
repeat for both UI and API
npm i redux react-redux redux-devtools-extension -S
Cycle
App.js should be set up as normal React with a state...
/App/App.js
What is in state that you want in store? Identify the method...
Action Creator Create directory and files
/src/
mkdir Actions
touch index.js
Create action in index.js
Name variable the same as the method
export const actionName = payLoadName => ({
type: 'YELL_ACTION_NAME',
payLoadName
});
No need to export or import anything
Reducer Create directory and files
Name individual reducer file what you would name the property in state
Create an individual reducer file for each property in state we want to update
/src/
mkdir Reducers
touch index.js todos.js
Create reducer in todos.js file
export const nameOfProperty = (state = [], action) => {
switch (action.type) {
case 'TYPE_NAME':
return action.payLoadName
default:
return state;
}
}
Ex reducer with multiple cases:
export const nameOfProperty = (state = [], action) => {
switch (action.type) {
case 'TYPE_NAME_1':
return action.payLoadName
case 'TYPE_NAME_ADD_2':
return [...state, action.payLoadName]
case 'TYPE_NAME_DELETE_3':
state = state.filter(item => item.item_id !== action.id)
return state
case 'TYPE_NAME_LOGOUT_4':
state = []
return state
default:
return state
}
}
Combine Reducers Either create the roote reducer and/or add the reducer to the rootReducer
/reducers/index.js
import { combineReducers } from 'redux';
import { reducerName } from './reducerName'; // reducer, must import each reducer
const rootReducer = combineReducers({
reducerName
});
export default rootReducer;
Set Up In Index Time to set up the store
/src/index.js
Import: Provider, createStore, composeWithDevTools, rootReducer
Create store
Wrap App
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import rootReducer from './reducers';
const store = createStore(rootReducer, composeWithDevTools());
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Go to console, redux tool, check to see if state is updated
Connect React Components To Store mapDispatchToProps Do you need to send information to the store?
Go to that file
Import: connect, action, maybe bindActionCreators
Make sure to assign method to props
Create mapDispatchToProps
Edit export with connect
import { connect } from 'react-redux';
import { actionName } from '../actions';
import { bindActionCreators } from 'redux';
class AddTodoForm extends Component {
funcName = () => {
const { actionName } = this.props;
actionName(this.state);
}
render(){
}
}
export const mapDispatchToProps = dispatch => ({
actionName: item => dispatch( actionName(item) )
})
// OR
export const mapDispatchToProps = (dispatch) => (
bindActionCreators(
{
actionName,
},
dispatch,
)
);
export default connect(null, mapDispatchToProps)(Component);
mapStateToProps Do you need to get information from the store?
Go to that file
Import: connect, action
Create mapStateToProps
Edit export with connect
import { connect } from 'react-redux';
const funcName = ({ itemInStoreName }) => {
const displayWhatever = itemInStoreName.map(singularItemInStoreName => {
return (
<Component
{...singularItemInStoreName}
key={singularItemInStoreName.id}
/>
)
})
return (
<ul>
{displayWhatever}
</ul>
)
}
const mapStateToProps = state => ({
itemInStoreName: state.itemInStoreName
});
export default connect(mapStateToProps, null)(ToDoList);
actions
import * as actions from '../actions';
describe('actions', () => {
describe('actionName', () => {
it('should have a type of TYPE_NAME', () => {
const whatYouAreFeedingTheAction = [
{
key: value,
key: value
},
{
key: value,
key: value
}
]
const expectedAction = {
type: 'TYPE_NAME',
varInAction: [
{
key: value,
key: value
},
{
key: value,
key: value
}
]
}
const result = actions.actionName(varFeedingToTheAction);
expect(result).toEqual(expectedAction);
});
});
});
Reducers
import { reducerName } from './reducerName';
describe('reducerName', () => {
it('should return the initial state', () => {
const expected = [];
const result = reducerName(undefined, {});
expect(result).toEqual(expected);
});
it('should add payLoadName to state', () => {
const initialState = [];
const mockNewPayLoadName = {
name: 'Quinne Farenwald'
};
const state = initialState;
const action = {
type: 'TYPE_NAME',
payloadName: mockNewPayLoadName
};
const newState = [...initialState, mockNewPayLoadName];
const result = reducerName(state, action);
expect(result).toEqual(newState);
});
});