0.0.1 • Published 5 years ago

react-akita v0.0.1

Weekly downloads
-
License
ISC
Repository
github
Last release
5 years ago

React Akita

React bindings for Akita.

Example

Let's implement a counter.

JavaScript

AkitaState.js (Shared)

import { Store, StoreConfig, Query } from "@datorama/akita";

export function createInitialState() {
  return {
    count: 0,
  };
}

@StoreConfig({ name: "count" })
class CountStore extends Store {
  constructor() {
    super(createInitialState());
  }
}

class CountQuery extends Query {
  count$ = this.select((state) => state.count);
}

class CountService {
  constructor(store) {
    this.store = store;
  }

  increment() {
    this.store.update({ count: this.store.getValue().count + 1 });
  }
}

export const store = new CountStore();
export const query = new CountQuery(store);
export const service = new CountService(store);

Akita Only

App.js

import React from "react";
import "./App.css";
import AkitaCounter from "./AkitaCounter";

function App() {
  return (
    <div className="App">
      <AkitaCounter />
    </div>
  );
}

export default App;

AkitaCounter.js

import React from "react";
import { query, service } from "./AkitaState";
import { untilUnmounted } from "./take-until";

export default class AkitaCounter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  componentDidMount() {
    query.count$
      .pipe(untilUnmounted(this))
      .subscribe((count) => this.setState({ count }));
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => service.increment()}>Click me</button>
      </div>
    );
  }
}

take-until.js (Helper)

import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";

export const untilUnmounted = (
  componentInstance,
  destroyMethodName = "componentWillUnmount"
) => (source) => {
  const originalDestroy = componentInstance[destroyMethodName];

  if (!componentInstance["__takeUntilDestroy"]) {
    componentInstance["__takeUntilDestroy"] = new Subject();

    componentInstance[destroyMethodName] = function () {
      typeof originalDestroy === "function" &&
        originalDestroy.apply(this, arguments);
      componentInstance["__takeUntilDestroy"].next(true);
      componentInstance["__takeUntilDestroy"].complete();
    };
  }

  return source.pipe(takeUntil(componentInstance["__takeUntilDestroy"]));
};

Akita with React Akita

App.js

import React from "react";
import "./App.css";
import ReactAkitaCounter from "./ReactAkitaCounter";
import { query, service } from "./AkitaState";
import { Provider } from "react-akita";

const rootQuery = {
  counterQuery: query,
};

const rootService = {
  counterService: service,
};

function App() {
  return (
    <div className="App">
      <Provider rootQuery={rootQuery} rootService={rootService}>
        <ReactAkitaCounter />
      </Provider>
    </div>
  );
}

export default App;

ReactAkitaCounter.js

import React from "react";
import { connect } from "react-akita";

function ReactAkitaCounter(props) {
  return (
    <div>
      <p>You clicked {props.count} times</p>
      <button onClick={props.increment}>Click me</button>
    </div>
  );
}

const mapQueryToProps = ({ counterQuery }) => ({ count: counterQuery.count$ });

const mapServiceToProps = ({ counterService }) => ({
  increment: () => counterService.increment(),
});

export default connect(mapQueryToProps, mapServiceToProps)(ReactAkitaCounter);

As you may see we not only decreased amount of the code we need to write but also we were able to use a function component instead a class component.

0.0.1

5 years ago