mirror of
https://github.com/mmalmi/mmalmi.github.io.git
synced 2025-06-03 16:02:04 +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?
|
||||
|
||||
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).
|
||||
```jsx
|
||||
@ -28,10 +28,8 @@ Then create a React component that uses the state:
|
||||
|
||||
```jsx
|
||||
class TextInput extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {text:''};
|
||||
}
|
||||
state = {text:''};
|
||||
|
||||
componentDidMount() {
|
||||
State.get('text').on(text => this.setState({text}));
|
||||
}
|
||||
@ -52,4 +50,56 @@ class TextInput extends React.Component {
|
||||
|
||||
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