/react-web-tips

Collection of tips when developing a react application

react-web-tips, Flux and Redux tips

Collection of tips when developing a react website NOT YET VISITED BY ME pen egg dan

Navigation Tips

  • use through history let {history} = this.props; history.isActive('home') // true or false
  • use <Link> tag with <Link activeClass={path}> attribute
  • to ignore or url params or query params, enclose path attribute in your Route like this
    ex: <Route path="archives(/:article)" name="archives" component={Archives}></Route>

alt text

Style

  • passing style to attribute style in the markup
const containerStyle = {
  marginTop: "60px"
};
<div class="container" style={containerStyle}></div>
  • snakeCasing is smart enough to identify "margin-top" css

Immutable through referencing in Object

use Object.assign $.extend _.extend _.assign

var a = {name:"Will", age: 35};
var b = Object.assign({}, a, {name: "Fred"});
b // Object {name: "Fred", age: 35}
a // Object {name: "Will", age: 35 }

Immutable through referencing in Array

use concat, filter map and reduce

var a = [0,1,2]
var b = a.concat(3)
a // [0,1,2]
b // [0,1,2,3]
var c = a.filter((val) => val !== 2)
c // [0,1]
a // [0,1,2]

Explained simple redux manifesto

import {createStore} from 'redux';
const reducer = function(state, action){
    let {type, payload} = action;
    if(type === "INC"){
        return state+=payload;
    }
    if(type === "DEC"){
        return state-=payload;
    }
    return state;
}
const store = createStore(reducer, 0);
store.subscribe( () => {
    console.log('hey store changed', store.getState())
});
store.dispatch({type: "INC", payload: 1});
store.dispatch({type: "INC", payload: 2});
store.dispatch({type: "INC", payload: 22});
store.dispatch({type: "INC", payload: 1});
store.dispatch({type: "DEC", payload: 1000});

Another Sample, setting your state Immutably

import {combineReducers, createStore} from 'redux';
const userReducer = (state = {}, action) => {
    switch(action.type){
        case 'CHANGE_USER': 
            state = {...state, name: action.payload}
        break;
        case 'CHANGE_AGE': 
            state = {...state, age: action.payload}
        break;
    }
    return state;
};
const tweetsReducer = (state =[], action) => {
    let arr = [];
    switch(action.type){
        case 'CHANGE_USER':
        arr = state.concat('entry');
        break;
    }
    return (arr.length === 0) ? state : arr;
};
const reducer = combineReducers({
    user: userReducer,
    tweets: tweetsReducer
});
const store = createStore(reducer);
store.subscribe( () => {
    console.log('hey store changed', store.getState())
});
store.dispatch({type: 'CHANGE_USER', payload: 'Dom'});
store.dispatch({type: 'CHANGE_USER', payload: 'Dom'});
store.dispatch({type: 'CHANGE_AGE', payload: 35});

Simple Middleware

import {applyMiddleware, combineReducers, createStore} from 'redux';
const userReducer = (state = {}, action) => {
    switch(action.type){
        case 'CHANGE_USER': 
            state = {...state, name: action.payload}
        break;
        case 'CHANGE_AGE': 
            state = {...state, age: action.payload}
        break;
    }
    return state;
};
const tweetsReducer = (state =[], action) => {
    let arr = [];
    switch(action.type){
        case 'CHANGE_USER':
        arr = state.concat('entry');
        break;
        case 'ERROR': 
            throw new Error('Intentionally Error!');
        break;
    }
    return (arr.length === 0) ? state : arr;
};
const reducer = combineReducers({
    user: userReducer,
    tweets: tweetsReducer
});
const logger = (store) => (next) => (action) => {
    console.log("action fired", action);
    // action.type = "CHANGE_AGE";
    next(action);
};
const error = (store) => (next) => (action) => {
    try {
        next(action);
    } catch(e){
        console.log('Exception', e);
    }
}
const middleware = applyMiddleware(logger, error);
const store = createStore(reducer, middleware);
store.subscribe( () => {
    console.log('hey store changed', store.getState())
});
store.dispatch({type: 'CHANGE_USER', payload: 'Dom'});
store.dispatch({type: 'CHANGE_USER', payload: 'Dom'});
store.dispatch({type: 'CHANGE_AGE', payload: 35});
store.dispatch({type: 'ERROR', payload: 35});

Redux Thunk

import {applyMiddleware, createStore} from 'redux';
import axios from 'axios';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
const initialState = {
    fetching: false,
    fetched: false,
    users: [],
    error: null
};
const reducer = (state = initialState, action) => {
    switch(action.type){
        case "FETCH_USERS_START":{
            return { ...state, fetching: true};
            break;
        }
        case "FETCH_USERS_ERROR": {
            return { ...state, fetching: false, error: action.payload};
            break;
        }
        case "RECEIVE_USERS": {
            return { ...state, fetching: false, fetched: true, users: action.payload};
            break;
        }
    }
    return state;
}
const middleware = applyMiddleware(thunk, logger());
const store = createStore(reducer, middleware);
store.dispatch( (dispatch) => {
    dispatch({type: "FETCH_USERS_START"});

    axios.get("http://rest.learncode.academy/api/wstern/users")
        .then( (response) =>{
            dispatch({type: "RECEIVE_USERS", payload: response.data})
        })
        .catch( (err) => {
            dispatch({type: "FETCH_USERS_ERROR", payload: err})
        });
});

Redux Promise

import {applyMiddleware, createStore} from 'redux';
import axios from 'axios';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import promise from 'redux-promise-middleware';

const initialState = {
    fetching: false,
    fetched: false,
    users: [],
    error: null
};
const reducer = (state = initialState, action) => {
    switch(action.type){
        case "FETCH_USERS_START":{
            return { ...state, fetching: true};
            break;
        }
        case "FETCH_USERS_ERROR": {
            return { ...state, fetching: false, error: action.payload};
            break;
        }
        case "RECEIVE_USERS": {
            return { ...state, fetching: false, fetched: true, users: action.payload};
            break;
        }
    }
    return state;
}
const middleware = applyMiddleware(promise(), logger());

const store = createStore(reducer, middleware);
store.dispatch({
    type: "FOO",
    payload: axios.get("http://rest.learncode.academy/api/wstern/users")
});

Changing Values with DOT (.) notation

import {createStore} from 'redux';
const initialState = {
    result: 1,
    lastValues: [],
    username: "Max"
}
const reducer = (state = initialState, action) =>{
    
    switch(action.type){
        case 'ADD':
            state = {
                ...state, 
                result: state.result + action.payload,
                lastValues: [...state.lastValues, action.payload] // or lastValues: state.lastValues.concat(action.payload)
            };
            // wrong: state.lastValues.push(action.payload);
            // wrong: state.result += action.payload;
        break;
        case 'SUBTRACT':
            state = {
                ...state, 
                result: state.result - action.payload,
                lastValues: [...state.lastValues, action.payload] // or lastValues: state.lastValues.concat(action.payload)
            };
            // wrong: state.lastValues.push(action.payload);
            // wrong: state.result -= action.payload;
        break;
    }
    return state;
};
const store = createStore(reducer);
store.subscribe( () => {
    console.log('Store updated!', store.getState())
});
store.dispatch({type: "ADD", payload: 100});
store.dispatch({type: "ADD", payload: 22});
store.dispatch({type: "SUBTRACT", payload: 80});

Custom Logger

import {createStore, combineReducers, applyMiddleware} from 'redux';
const mathReducer = (state = {
    result: 1,
    lastValues: [] 
    }, 
    action) =>{
    switch(action.type){
        case 'ADD':
            state = {
                ...state,
                result: state.result + action.payload,
                lastValues: [...state.lastValues, action.payload]
            };
        break;
        case 'SUBTRACT':
            state = {
                ...state,
                result: state.result - action.payload,
                lastValues: [...state.lastValues, action.payload]
            };
        break;
    }
    return state;
};
const userReducer = (state = {
    name: "Max",
    age: 27 
    }, 
    action) =>{
    switch(action.type){
        case 'SET_NAME':
            state = {
                ...state,
                name: action.payload,
            };
        break;
        case 'SET_AGE':
            state = {
                ...state,
                age: action.payload,
            };
        break;
    }
    return state;
};
const myLogger = (store) => (next) => (action) => {
    console.log('Logged Action:', action);
    next(action);
};
const store = createStore( combineReducers({mathReducer, userReducer}), {}, applyMiddleware(myLogger) );
store.subscribe( () => {
    console.log('Store updated!', store.getState())
});
store.dispatch({type: "ADD", payload: 100});
store.dispatch({type: "ADD", payload: 22});
store.dispatch({type: "SUBTRACT", payload: 80});
store.dispatch({type: "SET_AGE", payload: 30});

Redux Logger

import {createStore, combineReducers, applyMiddleware} from 'redux';
import logger from 'redux-logger';

const mathReducer = (state = {
    result: 1,
    lastValues: [] 
    }, 
    action) =>{
    switch(action.type){
        case 'ADD':
            state = {
                ...state,
                result: state.result + action.payload,
                lastValues: [...state.lastValues, action.payload]
            };
        break;
        case 'SUBTRACT':
            state = {
                ...state,
                result: state.result - action.payload,
                lastValues: [...state.lastValues, action.payload]
            };
        break;
    }
    return state;
};
const userReducer = (state = {
    name: "Max",
    age: 27 
    }, 
    action) =>{
    switch(action.type){
        case 'SET_NAME':
            state = {
                ...state,
                name: action.payload,
            };
        break;
        case 'SET_AGE':
            state = {
                ...state,
                age: action.payload,
            };
        break;
    }
    return state;
};
const myLogger = (store) => (next) => (action) => {
    console.log('Logged Action:', action);
    next(action);
};
const store = createStore( combineReducers({mathReducer, userReducer}), {}, applyMiddleware( myLogger, logger() ));
store.subscribe( () => {
    console.log('Store updated!', store.getState())
});
store.dispatch({type: "ADD", payload: 100});
store.dispatch({type: "ADD", payload: 22});
store.dispatch({type: "SUBTRACT", payload: 80});
store.dispatch({type: "SET_AGE", payload: 30});