Redux is a predictable state container for JavaScript app
actions
function getData() {
return {
type: FETCHING_DATA
}
}
function getDataSuccess(data) {
return {
type: FETCHING_DATA_SUCCESS,
data,
}
}
function getDataFailure() {
return {
type: FETCHING_DATA_FAILUR
}
}
reducers
const initialState = {
data: [],
dataFetched: false,
isFetching: false,
error: false,
}
function dataReducer(state = initialState, action) {
switch(action.type) {
case FETCHING_DATA:
return {
...state,
isFetching: true,
}
case FETCHING_DATA_SUCCESS:
return {
...state,
isFetching: false,
data: action.data,
}
case FETCHING_DATA_FAILURE:
return {
...state,
isFetching: false,
error: true,
}
}
}
create-react-app ReactRedux
cd ReactRedux
yarn add redux react-redux
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import { Provider } from 'react-redux'
import configureStore from './configureStore'
const store = configureStore()
const ReduxApp = () => (
<Provider store={store}>
<App />
</Provider>
)
ReactDOM.render(
<ReduxApp />,
document.getElementById('root')
);
index.js
create redux files
Reducers folder
configureStore.js
constants.js
actions.js
Reducers - index.js
import { combineReducers } from 'redux'
import appData from './dataReducer'
const rootReducer = combineReducers({
appData
})
export default rootReducer
Reducers - dataReducer.js
import { FETCHING_DATA, FETCHING_DATA_SUCCESS, FETCHING_DATA_FAILURE } from '../constants'
const initialState = {
data: [],
dataFetched: false,
isFetching: false,
error: false,
}
export default function dataReducer(state = initialState, action) {
switch(action.type) {
case FETCHING_DATA:
return {
...state,
data: [],
isFetching: true,
}
case FETCHING_DATA_SUCCESS:
return {
...state,
isFetching: false,
data: action.data,
}
case FETCHING_DATA_FAILURE:
return {
...state,
isFetching: false,
error: true,
}
default:
return state
}
}
actions.js
import { FETCHING_DATA, FETCHING_DATA_SUCCESS, FETCHING_DATA_FAILURE } from './constants'
export function getData() {
return {
type: FETCHING_DATA
}
}
export function getDataSuccess(data) {
return {
type: FETCHING_DATA_SUCCESS,
data,
}
}
export function getDataFailure() {
return {
type: FETCHING_DATA_FAILURE
}
}
export function fetchData() {}
configureStore.js
import { createStore } from 'redux'
import app from './reducers'
export default function configureStore() {
let store = createStore(app)
return store
}
constants.js
export const FETCHING_DATA = 'FETCHING_DATA'
export const FETCHING_DATA_SUCCESS = 'FETCHING_DATA_SUCCESS'
export const FETCHING_DATA_FAILURE = 'FETCHING_DATA_FAILURE'
app.js
import { connect } from 'react-redux'
import { fetchData } from './actions'
import connect from redux + reducer
Text
function mapStateToProps (state) {
return {
appData: state.appData,
}
}
function mapDispatchToProps(dispatch) {
return {
fetchData: () => dispatch(fetchData())
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App)
attach actions and props to the component
app.js
console.log('props:', this.props);
create fake api (api.js)
Text
const people = [
{ name: 'Nader', age: 36 },
{ name: 'Amanda', age: 24 },
{ name: 'Jason', age: 44 }
]
export default () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve(people)
}, 4000)
});
}
thunk middleware
yarn add redux-thunk
update configureStore.js
import { createStore, applyMiddleware } from 'redux'
import app from './reducers'
import thunk from 'redux-thunk';
export default function configureStore() {
let store = createStore(app, applyMiddleware(thunk))
return store
}
update actions.js
import getPeople from '.api'
export function fetchData() {
return (dispatch) => {
dispatch(getData())
getPeople()
.then((data) => {
dispatch(getDataSuccess(data))
})
.catch((err) => console.log('err:', err))
}
}
update app.js
{
this.props.appData.isFetching ? <p>Loading</p> :
<p onClick={() => this.props.fetchData()}>Fetch Data</p>
}
{
this.props.appData.data.length ? (
this.props.appData.data.map((person, i) => {
return <div key={i}>
<p>Name: {person.name}</p>
<p>Age: {person.age}</p>
</div>
})
) : null
}
yarn add redux-saga
import { FETCHING_DATA, FETCHING_DATA_SUCCESS, FETCHING_DATA_FAILURE } from './constants'
import { put, takeEvery } from 'redux-saga/effects'
import getPeople from './api'
function* fetchData(action) {
try {
const data = yield getPeople()
yield put({ type: FETCHING_DATA_SUCCESS, data });
} catch (e) {
yield put({type: FETCHING_DATA_FAILURE });
}
}
function* dataSaga() {
yield takeEvery(FETCHING_DATA, fetchData);
}
export default dataSaga;
saga.js
import { createStore, applyMiddleware } from 'redux'
import app from './reducers'
import createSagaMiddleware from 'redux-saga'
import dataSaga from './sagas'
const sagaMiddleware = createSagaMiddleware()
export default function configureStore() {
const store = createStore(app, applyMiddleware(sagaMiddleware))
sagaMiddleware.run(dataSaga)
return store
}
configureStore.js
import { FETCHING_DATA } from './constants'
export function fetchData() {
return {
type: FETCHING_DATA
}
}
actions.js