mirror of
https://github.com/mmalmi/mmalmi.github.io.git
synced 2025-06-06 18:31:07 +00:00
.
This commit is contained in:
parent
5c231b32d7
commit
ad5e477acc
@ -12,7 +12,7 @@ image: https://siriusbusiness.fi/assets/images/posts/painless.jpg
|
|||||||
|
|
||||||
Fed up with writing a ton of Redux boilerplate just to make a form input editable?
|
Fed up with writing a ton of Redux boilerplate just to make a form input editable?
|
||||||
|
|
||||||
There’s a better alternative: [Gun.js](https://github.com/amark/gun). It makes state synchronization and persistence super easy.
|
There’s a better alternative: [Gun.js](https://github.com/amark/gun). It makes state synchronization and persistence a breeze.
|
||||||
|
|
||||||
First, initialize Gun with options that make sure the state is synced with localStorage only (not with peers).
|
First, initialize Gun with options that make sure the state is synced with localStorage only (not with peers).
|
||||||
```jsx
|
```jsx
|
||||||
@ -28,10 +28,8 @@ Then create a React component that uses the state:
|
|||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
class TextInput extends React.Component {
|
class TextInput extends React.Component {
|
||||||
constructor() {
|
state = {text:''};
|
||||||
super();
|
|
||||||
this.state = {text:''};
|
|
||||||
}
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
State.get('text').on(text => this.setState({text}));
|
State.get('text').on(text => this.setState({text}));
|
||||||
}
|
}
|
||||||
@ -53,3 +51,55 @@ class TextInput extends React.Component {
|
|||||||
Now you have a text form that syncs its content across component instances and persists it in localStorage.
|
Now you have a text form that syncs its content across component instances and persists it in localStorage.
|
||||||
|
|
||||||
See the working example on [Codepen](https://codepen.io/mmalmi/pen/VwWVdKG).
|
See the working example on [Codepen](https://codepen.io/mmalmi/pen/VwWVdKG).
|
||||||
|
|
||||||
|
However, if we now unmount the component and write to `State.get('text')` elsewhere, we'll get the warning: `Can't call setState on an unmounted component. This is a no-op, but it indicates a memory leak in your application.`
|
||||||
|
|
||||||
|
We can avoid that by saving our state subscriptions and unsubscribing them in `componentWillUnmount()`. Here's a helper class for that:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class BaseComponent extends React.Component {
|
||||||
|
subscriptions = {};
|
||||||
|
|
||||||
|
subscribe(callback, path) {
|
||||||
|
return (value, key, x, subscription, f) => {
|
||||||
|
if (this.unmounted) {
|
||||||
|
subscription && subscription.off();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.subscriptions[path || key] = subscription;
|
||||||
|
callback(value, key, x, subscription, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inject(name, path) {
|
||||||
|
return this.subscribe((v,k) => {
|
||||||
|
const newState = {};
|
||||||
|
newState[name || k] = v;
|
||||||
|
this.setState(newState);
|
||||||
|
}, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.unmounted = true;
|
||||||
|
Object.keys(this.subscriptions).forEach(k => {
|
||||||
|
const subscription = this.subscriptions[k];
|
||||||
|
subscription && subscription.off();
|
||||||
|
delete this.subscriptions[k];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we can extend BaseComponent, which takes care of injecting values to the component's state and unsubscribing on unmount.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
class TextInput extends BaseComponent {
|
||||||
|
// ...
|
||||||
|
componentDidMount() {
|
||||||
|
State.get('text').on(this.inject());
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[Codepen](https://codepen.io/mmalmi/pen/MWozPZE)
|
Loading…
x
Reference in New Issue
Block a user