Reputation: 123
I am using redux for state management for a dynamic grid where someone can add their own components. I'm using this library for the grid https://github.com/STRML/react-grid-layout .
I want to use Gun as a persistence layer for storing & replicating the current state of the grid & its components into a user profile. my app does not use Express.js for now so I'm having some issues running the examples since all of them use Express. I'm also using react-gun but I was not able to figure out how to setup the Gun Provider with the Redux Store Provider
is there a canonical method/example to use Gun with Redux for React?
i've tried this
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import Gun from 'gun';
import { GunProvider } from 'react-gun';
import App from './App';
import configureStore from './redux/store/configureStore';
import * as serviceWorker from './serviceWorker';
const gun = Gun({ file: 'db' });
ReactDOM.render(
<GunProvider gun={gun}>
<Provider store={configureStore()}>
<App />
</Provider>
</GunProvider>,
document.getElementById('root')
);
serviceWorker.unregister();
and this
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import Gun from 'gun';
import { GunProvider } from 'react-gun';
import App from './App';
import configureStore from './redux/store/configureStore';
import * as serviceWorker from './serviceWorker';
const gun = Gun({ file: 'db' });
ReactDOM.render(
<Provider store={configureStore()}>
<GunProvider gun={gun}>
<App />
</GunProvider>
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
i do not see any errors building or running the app
console log start
[HMR] Waiting for update signal from WDS...
gun.js:863 Hello wonderful person! :) Thanks for using GUN, feel free to ask for help on https://gitter.im/amark/gun and ask StackOverflow questions tagged with 'gun'!
console log showing the 'data' variable i logged in the code above
data: Gun
_:
$: Gun {_: {…}}
ack: 1
back: {gun: Gun, $: Gun, opt: {…}, root: {…}, graph: {…}, …}
get: "data"
gun: Gun {_: {…}}
id: 79
on: ƒ onto(tag, arg, as)
put: undefined
root: {gun: Gun, $: Gun, opt: {…}, root: {…}, graph: {…}, …}
soul: "data"
tag: {in: {…}, out: {…}}
__proto__: Object
__proto__: Object
but i dont see anything appearing in Chrome >> Application tab >> Local Storage
i see this in yarn build
logs but i am not sure it is related
WARNING in ../node_modules/gun/gun.js 10:16-28
Critical dependency: the request of a dependency is an expression
@ ./index.jsx
here's how i use yarn to build/run the project package.json
"scripts": {
"start": "cross-env-shell NODE_ENV=development node --max-old-space-size=12288 node_modules/webpack-dev-server/bin/webpack-dev-server.js --mode development --open",
"build": "cross-env-shell NODE_ENV=production node --max_old_space_size=12288 node_modules/webpack/bin/webpack.js --mode production",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
here's how i use gun in my components
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { withGun } from 'react-gun';
import Logger from '../appLogger/logger';
const log = new Logger({
childType: 'component',
childName: 'Foo'
});
class Foo extends Component {
static propTypes = {
blah: PropTypes.string.isRequired
};
constructor(props) {
super(props);
}
componentDidMount() {
const data = this.props.gun.get('data').once(() => {});
log.debug({
msg: '[component] [componentDidMount] MainLayout',
methodType: 'componentDidMount',
logObjectName: 'data',
logObject: data
});
}
render() {
const { blah } = this.props;
return (
<div>
{blah}
</div>
);
}
}
export default withGun(Foo);
Expected results -
I should see an entry called "gun" Chrome DevTools >> Application tab >> Local Storage
Actual Results -
i dont see anything appearing in Chrome Chrome DevTools >> Application tab >> Local Storage
Upvotes: 3
Views: 665
Reputation: 922
Upfront disclosure: I'm the developer of a competing library which isn't out of beta yet (will probably get renamed): https://github.com/rm-rf-etc/react-gun
The react-gun
library you're using seems rather pointless to me. You can accomplish more with less code by removing it.
Somewhere in your project, include:
// ./setup-gun.js
import Gun from 'gun/gun';
const gun = Gun();
export default gun.get('app_root');
As we discussed on gitter, I recommend binding your gun data directly to react components, which looks like the following. But if you have to use redux, then skip to the redux example.
Inside your component, use hooks to trigger the update when data comes in. Like this:
// ./index.js
import React from 'react';
import node from './setup-gun.js';
export const Component = () => {
const ref = React.useRef(null);
const [count, setCount] = React.useState(0);
ref.current = count;
const increment = React.useCallback(() => setCount(ref.current + 1));
React.useEffect(() => {
node.get('count').on((val) => setCount(val));
// you will also need to capture and store a reference to `chain.off`
// inside of `.on` so you can call it when the component unmounts:
// return () => listeners.forEach(l => l.off())
}, []);
return (
<div>
<button onClick={increment}>Increment</button>
<div>{ref.current}</div>
</div>
);
};
If you have more than one piece of state data to manage, you can replace useState
with useReducer
.
// ./gun-redux.js
import node from './setup-gun.js';
import { setCount } from './actions.js';
// export store after you configure it
import store from './store.js';
// trigger action from gun listener, will fire when count changes
node.get('count').on((val) => store.dispatch(setCount(val)));
// ./index.js
import React from 'react';
import node from './gun.js';
const countNode = node.get('count');
const increment = () => countNode.once((val) => countNode.put(val + 1));
const Component = ({ count }) => (
<div>
<button onClick={increment}>Increment</button>
<div>{count}</div>
</div>
);
const mapStateToProps = (state) => ({
count: state.count,
});
export default connect(mapStateToProps)(Component);
I think the former approach (without redux) will be less confusing. Using gun makes redux kinda pointless because you can read the current state and get your updates directly from gun, so using redux creates unnecessary duplication of functionality in your framework.
This example assumes you're reading a count property directly off the app root in gun. Obviously you'll want to do something more like const countNode = node.get(recordId).get('count');
, where recordId
is the string ID for whichever data entry you're binding to.
Upvotes: 2