https://github.com/alonrbar/react-peppermint
Fresh state management for React 🌿
https://github.com/alonrbar/react-peppermint
dependency-injection mvvm react typescript viewmodel
Last synced: about 1 month ago
JSON representation
Fresh state management for React 🌿
- Host: GitHub
- URL: https://github.com/alonrbar/react-peppermint
- Owner: alonrbar
- License: mit
- Created: 2018-05-16T19:00:27.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2024-08-08T14:29:00.000Z (11 months ago)
- Last Synced: 2025-02-17T06:51:20.384Z (4 months ago)
- Topics: dependency-injection, mvvm, react, typescript, viewmodel
- Language: TypeScript
- Homepage:
- Size: 1.79 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# react-peppermint
Fresh state management for React 🌿
[](https://github.com/alonrbar/react-peppermint/actions/workflows/ci.yaml)
[](https://www.npmjs.com/package/react-peppermint)
[](https://github.com/alonrbar/react-peppermint/blob/master/LICENSE)- [The gist](#the-gist)
- [Installation](#installation)
- [Provider](#provider)
- [View models](#view-models)
- [Class components](#class-components)
- [Function components](#function-components)
- [Changelog](#changelog)## The gist
```typescript
import { action, useViewModel, viewModel } from 'react-peppermint';//
// View model
//@viewModel
class CounterVm {public count = 0;
@action
public increment() {
this.count++;
}
}//
// Component
//function Counter() {
const vm = useViewModel(CounterVm)
return (
<>
{vm.count}
Increment
>
);
}
```## Installation
```shell
yarn add react-peppermint
```or
```shell
npm install --save react-peppermint
```## Provider
React Peppermint includes a `` component, which makes the view models available to the rest of your application:
```typescript
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-peppermint';
import App from './app';
import { resolver } from './resolver';const root = createRoot(document.getElementById("root"));
root.render(
);
```The provider needs a `Resolver`. The resolver is a [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) container.
React Peppermint is not tied to any specific container, use poor man's DI or your container of choice.To keep it simple in this example we
use a standard JavaScript [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) as our DI container:```typescript
import { IResolver } from 'react-peppermint';
import { AppVm } from './appVm';
import { CounterVm } from './counterVm';const container = new Map();
container.set(AppVm, new AppVm());
container.set(CounterVm, new CounterVm());// Implement the IResolver interface
export const resolver: IResolver = {
get: (key: any) => {
return container.get(key);
}
};
```> [!TIP]
> We recommend the excellent [peppermint-di](https://github.com/alonrbar/peppermint-di) container :wink:## View models
View models hold state and logic to be used by your components.
First, annotate the class with the `viewModel` decorator. Then, add fields and method as usual.
Now, in order for a view-model method to cause a refresh of the component it's connected to, we need to annotate it with a decorator. There are four types of method decorators in React Peppermint:
1. `action` - This is the basic method decorator. It causes any connected component to re-render when the method is done.
2. `broadcast` - This decorator will cause _all_ connected components to re-render, whether they are connected to this view model or any other view model.
3. `activate` - Instructs React Peppermint to invoke this method after the first time the component is mounted (similarly to [componentDidMount](https://react.dev/reference/react/Component#componentdidmount)).
4. `deactivate` - Instructs React Peppermint to invoke this method right before the component will unmount (similarly to [componentWillUnmount](https://react.dev/reference/react/Component#componentwillunmount)).```typescript
import { action, activate, deactivate, viewModel } from 'react-peppermint';@viewModel
class CounterVm {public count = 0;
@activate
public activate() {
console.log('Hello!');
}@action
public increment() {
this.count++;
}@deactivate
public activate() {
console.log('Bye!');
}
}
```## Class components
To connect a view model to a class component, use the `withViewModel` high order component (don't worry if you are not familiar with the [HOC](https://legacy.reactjs.org/docs/higher-order-components.html) concept, you can think of it as a simple function).
```typescript
import * as React from 'react';
import { withViewModel } from 'react-peppermint';
import { CounterVm } from './counterVm';class Counter extends React.Component {
public render() {
return (
<>
{this.props.count}
Increment
>
);
}
}// Using the 'withViewModel' HOC here:
export default withViewModel(CounterVm)(Counter);
```## Function components
You can connect function components to view models by using the `withViewModel` HOC, exactly like it's done with class components. However, higher-order components are not commonly used in modern React code. Instead, hooks are the common way to go.
The **recommended** way to connect a function component to a view model is by using the `useViewModel` hook:
```typescript
import * as React from 'react';
import { useViewModel } from 'react-peppermint';
import { CounterVm } from './counterVm';export default function Counter() {
const vm = useViewModel(CounterVm)
return (
<>
{vm.count}
Increment
>
);
}
```## Changelog
The changelog can be found [here](https://github.com/alonrbar/react-peppermint/blob/master/CHANGELOG.md).