DEV Community

Cover image for React and Vue Syntax Comparison Side by Side Part3: State Management
Andrew
Andrew

Posted on

React and Vue Syntax Comparison Side by Side Part3: State Management

This is the third post about React and Vue syntax comparison. In this article, we will compare the syntax for the most famous state management library in both ecosystems - Redux & Vuex.

GitHub logo oahehc / react-vue-comparison

Comparing the syntax of React.js/Next.js and Vue.js/Nuxt.js side by side

Agenda


Create Store

Redux: https://redux.js.org/basics/store

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'

const store = createStore(todoApp)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
Enter fullscreen mode Exit fullscreen mode

Vuex: https://vuex.vuejs.org/guide/

const store = new Vuex.Store({
  state: { ... },
  mutations: { ... }
})

...

new Vue({
  el: '#app',
  store,
});
Enter fullscreen mode Exit fullscreen mode

Action

Redux: https://redux.js.org/basics/actions

const ADD_TODO = 'ADD_TODO'

function addTodo(text) {
  return {
    type: ADD_TODO,
    text,
  }
}
Enter fullscreen mode Exit fullscreen mode

Vuex: https://vuex.vuejs.org/guide/actions.html

const store = new Vuex.Store({
  actions: {
    increment (context) {
      context.commit('increment') // commit a mutation to trigger state update
    }
  }
})
Enter fullscreen mode Exit fullscreen mode

Async-Action

Redux(redux-thunk): https://redux.js.org/advanced/async-actions

// apply redux-thunk
import thunkMiddleware from 'redux-thunk'

const store = createStore(
  rootReducer,
  applyMiddleware(thunkMiddleware)
)

...

export function fetchPosts() {
  return function (dispatch) {
    dispatch(requestPosts())
    return fetch('xxx')
      .then(response => response.json())
      .then(json => dispatch(receivePosts(json)))
  }
}
Enter fullscreen mode Exit fullscreen mode

Vuex: https://vuex.vuejs.org/guide/actions.html

actions: {
  async fetchPosts ({ commit }) {
    commit('requestPosts');
    const res = await fetch('xxx');
    commit('receivePosts', res);
  },
}
Enter fullscreen mode Exit fullscreen mode

Reducer | Mutation

Redux(reducer): https://redux.js.org/basics/reducers

const initialState = {
  todos: [],
}

function todoApp(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO:
      return {
        ...state,
        todos: [
          ...state.todos,
          {
            text: action.text,
            completed: false,
          }
        ],
      }

    default:
      return state
  }
}
Enter fullscreen mode Exit fullscreen mode

Vuex(mutation): https://vuex.vuejs.org/guide/mutations.html

const store = new Vuex.Store({
  mutations: {
    addTodo (state, payload) {
      state.todos = [
        ...state.todos,
        { text: payload.text, completed: false }
      ]
    }
  }
})
Enter fullscreen mode Exit fullscreen mode

Combine-Reducers | Modules

Redux(combine-reducers): https://redux.js.org/api/combinereducers

import { combineReducers } from 'redux'

const reducers = combineReducers({
  reducerA,
  reducerB,
})

export default reducers
Enter fullscreen mode Exit fullscreen mode

Vuex(modules): https://vuex.vuejs.org/guide/modules.html

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})
Enter fullscreen mode Exit fullscreen mode

Connect-with-Component

Redux: https://redux.js.org/basics/usage-with-react

import { connect } from 'react-redux'
import { addTodo } from '../actions'
import TargetComp from '../components/TargetComp'

// state
const mapStateToProps = (state, ownProps) => {
  return {
    todos: state.todos,
  }
}

// action
const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    addTodo: (text) => {
      dispatch(addTodo(text))
    }
  }
}

const TargetContainer = connect(mapStateToProps, mapDispatchToProps)(TargetComp)

export default TargetContainer
Enter fullscreen mode Exit fullscreen mode

Vuex

state: https://vuex.vuejs.org/guide/state.html
import { mapState } from 'vuex'

export default {
  computed: {
    ...mapState(['count']),
  }
}
Enter fullscreen mode Exit fullscreen mode
action: https://vuex.vuejs.org/guide/actions.html
import { mapActions } from 'vuex'

export default {
  methods: {
    ...mapActions(['increment']),
  }
}
Enter fullscreen mode Exit fullscreen mode

Middleware | Plugin

Redux(middleware): https://redux.js.org/advanced/middleware

import { createStore, combineReducers, applyMiddleware } from 'redux'

const logger = store => next => action => {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  return result
}
const todoApp = combineReducers(reducers)
const store = createStore(
  todoApp,
  applyMiddleware(logger)
)
Enter fullscreen mode Exit fullscreen mode

Vuex(plugin): https://vuex.vuejs.org/guide/plugins.html

const myPluginWithSnapshot = store => {
  let prevState = _.cloneDeep(store.state)
  store.subscribe((mutation, state) => {
    let nextState = _.cloneDeep(state)

    // compare `prevState` and `nextState`...

    // save state for next mutation
    prevState = nextState
  })
}

const store = new Vuex.Store({
  ...,
  plugins: process.env.NODE_ENV !== 'production' ? [myPluginWithSnapshot] : [],
})
Enter fullscreen mode Exit fullscreen mode

Selector | Getter

Redux(reselect): https://redux.js.org/recipes/computing-derived-data

import { createSelector } from 'reselect'

const getTodos = state => state.todos

export const getDoneTodos = createSelector(
  [getTodos],
  todos.filter(t => t.completed),
)

...

import { connect } from 'react-redux'
import TodoList from '../components/TodoList'
import { getDoneTodos } from '../selectors'

const mapStateToProps = state => {
  return {
    doneTodos: getDoneTodos(state)
  }
}

const DoneTodoList = connect(mapStateToProps)(TodoList)

export default DoneTodoList
Enter fullscreen mode Exit fullscreen mode

Vuex: https://vuex.vuejs.org/guide/getters.html

const store = new Vuex.Store({
  state: { ... },
  getters: {
    doneTodos: state => {
      return state.todos.filter(t => t.completed)
    }
  }
})

...

import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters(['doneTodos'])
  }
}
Enter fullscreen mode Exit fullscreen mode

DevTools

Redux

https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd

Vuex

https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd


Reference

Top comments (3)

Collapse
 
nolimitsstudio profile image
NLS • Edited

Good article! It'll be great, if you make such compare for Angular and Vue

Collapse
 
oahehc profile image
Andrew

Thanks for the suggestion. Unfortunately, I'm not familiar with Angular yet. I will write an article about Angular and Vue if I have a chance to use Angular later.

Collapse
 
nanto88 profile image
Nanto

Thank you for the comparison!
my preference react is more readable and familiar