vvscode / js--vuejs-redux

High order component facilities for Vue and Redux

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

vuejs-redux

npm version Build Status

Description

Simple binding between Vue and Redux, allowing use of multiple stores. It works, in the same way, like render props does in React. It uses Scoped Slot - read my article about it.

Note: The previous version was using Higher Order Components (HOC); this version uses Scoped slots instead. No more magic with the connect methods. Everything is explicit which will prevent props collision and an ugly trick with the render function.

Why you should use it:

  • Just 45 lines of code.
  • No dependencies at all
  • Easy to read, understand, and extend.
  • Same API as react-redux.
  • Combine multiple Providers to be populated by multiple sources.
  • No hard coded dependencies between 'Vue' and the store, so more composable.
  • Doesn't polluate data, so you can use the power of the functional component
  • Debuggable in the Vue devtool browser extension.
  • Elegant JSX syntax.

Install

npm install --save vuejs-redux

Counter example

Let's build a simple counter app. The full code can be found in the example/ directory.

Start with a reducer:

export function counter(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    case 'RESET':
      return 0;
    default:
      return state;
  }
}

Create the action creators in order to update our state:

export function increment() {
  return { 'type': 'INCREMENT' };
}

export function decrement() {
  return { 'type': 'DECREMENT' };
}

export function reset() {
  return { type: 'RESET' }
}

We can now create the CounterProvider component. It acts as a Provider for our CounterComponent:

<template>
  <Provider :mapDispatchToProps="mapDispatchToProps" :mapStateToProps="mapStateToProps" :store="store">
    <template slot-scope="{counterValue, actions}"> <!-- We pass our state via slot-scope. Passing down the props to the component is no more hidden -->
      <Counter :counterValue="counterValue" :actions="actions" :title="title" /> <!-- explicitly pass other props (title) -->
    </template>
  </Provider>
</template>
import { createStore, bindActionCreators } from 'redux';
import Provider from 'vuejs-redux';
import * as Actions from '../Actions';
import Counter from './Counter.vue';
import { counter } from '../Reducers/Counter';

export default {

  methods: {
    mapStateToProps(state) {
      return {counterValue: state}
    },

    mapDispatchToProps(dispatch) {
      return {actions: bindActionCreators(Actions, dispatch)}
    }
  },

  components: {
    Counter,
    Provider
  },

  data: () => ({
    store: createStore(counter),
    title: 'Counter using vuejs-redux'
  })

}

And finally our Counter component:

<template functional> <!-- we can use functional component -->
  <div>
    <h1> Counter using vuejs-redux </h1>
    <div> {{ counterValue }} </div>
    <button @click="actions.increment()"> increment </button>
    <button @click="actions.decrement()"> decrement </button>
    <button @click="actions.reset()"> reset </button>
  </div>
</template>

<script>
  export default {
    props: ['actions', 'counterValue'] // provided by our Provider
  };
</script>

Our Counter component is not aware that we are using redux.

If you use JSX, you can use the same syntax as React render props:

render(h) {
    return (
      <Provider mapDispatchToProps={this.mapDispatchToProps} mapStateToProps={this.mapStateToProps} store={this.store}>
        {({actions, counterValue}) => (
          <Counter counterValue={counterValue} actions={actions} title={this.title} />
        )}
      </Provider>
    );
  },

Multiple stores

You can combine multiple store if needed, use the Provider component various times. You can obviously create an helper component or whatever to compose this.

<template>
  <Provider
    :store=storeOne
    :mapStateToProps=mapStateToPropsOne
    :mapDispatchToProps=mapDispatchToPropsOne>
      <template slot-scope="{myStateOne, myActionOne}">
        <!-- Use our second provider -->
        <Provider
          :store=storeTwo
          :mapStateToProps=mapStateToPropsTwo
          :mapDispatchToProps=mapDispatchToPropsTwo>
          <template slot-scope="{myStateTwo, myActionTwo}">
            <!-- render our component here -->
            <Child :stateOne=myStateOne :stateTwo=myStateTwo .../>
          </template>
        </Provider>
      </template>
    </Provider
</template>

This plugin is compatible with rematch: live example

CONTRIBUTING

Feel free to create issues or pull requests if needed.

About

High order component facilities for Vue and Redux


Languages

Language:JavaScript 55.2%Language:Vue 44.8%