DEV Community

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

Posted on

8 4

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

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

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

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay