-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to use with React Hooks #59
Comments
No idea yet. I am on a holiday with very limited internet. I will catch up with React news in a week when I get back. (I guess there is a lot of news) |
Yup lot of news! This is not a question only for this library but also for other state libraries like Mobx so I think by when your are back there might be some addition research from others on how to use, I will try to research my self. |
So this is what I have come up with so far: import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { store, view } from "react-easy-state";
import { observe, unobserve } from "@nx-js/observer-util";
const useEasyState = store => {
const [state, setState] = useState(store);
const handleStateChange = () => {
console.log(state);
setState({ ...state });
};
useEffect(
() => {
const fn = observe(handleStateChange);
return () => unobserve(fn);
},
[store]
);
return state;
};
const counter = store({
num: 0,
inc: () => {
return counter.num++;
}
});
const Counter = () => {
const { inc, num } = useEasyState(counter);
return <button onClick={inc}>{num}</button>;
};
function App() {
return (
<div className="App">
<Counter />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement); The import { useEasyState } from 'react-easy-state' Let me know what you think when you are back. |
Here is the working example: |
Hi. Just wanted to show what I've been trying out. |
Hi All! I am back 🙂 Thanks for all the demos so far, I will catch up with them in the afternoon. |
Thanks for the effort @cayasso and @penspinner. Here is my feedback/thoughts:
Something like: import React from "react";
import ReactDOM from "react-dom";
import { useStore } from "react-easy-state";
const counter = {
num: 0,
inc: () => {
return counter.num++;
}
};
const Counter = () => {
const { inc, num } = useStore(counter);
return <button onClick={inc}>{num}</button>;
};
const rootElement = document.getElementById("root");
ReactDOM.render(<Counter />, rootElement); There are two questions to consider:
Let me know what you think. EDIT: I didn't have time to do a demo yet, so I am not a 100% sure that this is doable. |
My 5 cents.
I'm fine with
I would say state is "local" or "global" depending on the file it's located in... and that's all. |
Yes. I know. It was cool to re-implement the view though. Who knows if hooks performance could be better than stateful class someday. One thing I'm not sure about is would import React from "react";
import ReactDOM from "react-dom";
import { useStore } from "react-easy-state";
const counter = {
num: 0,
inc: () => {
return counter.num++;
}
};
const Counter1 = () => {
const { inc, num } = useStore(counter);
return <button onClick={inc}>{num}</button>;
};
const Counter2 = () => {
const { inc, num } = useStore(counter);
return <button onClick={inc}>{num}</button>;
};
const App = () => (
<>
<Counter1 />
<Counter2 />
</>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement); |
Welcome back @solkimicreb hope you enjoyed your vacations!
const counter = {
num: 0,
inc: () => {
// won't work, it need a reference to "counterStore"
return counter.num++;
// will work because its a reference to reactive counterStore
return counterStore.numm++;
}
}
const counterStore = store(counter) |
Hi everyone. I have 2 questions here (and one big thank you for the amazing library!).
// globalstate.js
import { store } from 'react-easy-state';
const globalstate = store({
number: 0
});
export default globalstate; // MyComponent.js
import React from 'react';
import globalstate from './globalstate';
function MyComponent() {
return <p>my number is {globalstate.number}</p>;
}
export default view(MyComponent); Would it still be possible to import |
@nAndreas the update is not released yet. Current
To my understanding, everything is 100% backward compatible. It's only if you move to hooks in your code base – you'll need to apply this new API. |
I did some research and everything I wrote so far was more or less incorrect, sorry about that. Now I have a tiny working demo to back up the ideas. Big thanks @penspinner for your demo! My one is a slightly modified version of yours. I hoped to shrink the current API to a single hook, but it turned out that we have to keep both the This is the proposed API for the new use cases.
import React from 'react';
import ReactDOM from 'react-dom';
import { view, store } from 'react-easy-state';
// this is a global store which is shared between component instances
const globalStore = store({ show: true })
const toggleShow = () => (globalStore.show = !globalStore.show)
// using store inside a function component creates a local store that is not shared between component instances
const Counter = view(() => {
const localStore = store({ num: 12 })
const inc = () => localStore.num++
return <button onClick={inc}>{localStore.num}</button>
});
const App = view(() => (
<div>
{globalStore.show && <Counter />}
<button onClick={toggleShow}>Toggle Counter</button>
</div>
))
ReactDOM.render(<App />, document.getElementById('root')); You can find the codesandbox demo with the initial implementation here. Let me know what you think. |
@solkimicreb It looks great to me, I like the fact that we continue using the same API, there is one change only, I noticed that in
You can reproduce the error here https://codesandbox.io/s/l5nkkqqp0l notice what happen when you increment. The solution is to use |
Just tried your example. Looks fine except for a few things.
|
I hope to have some time over the weekend to implement this. Thanks for the feedback @penspinner
This is a bug, I will look into it.
This won't be an issue. Every hook must be called in the exact same order on every render. (This is a lower level equivalent oh the 'hook rules'). My EDIT: this might take some time. I think I will take the opportunity and rewrite enzyme tests. (Enzyme lags behind the latest React features.) EDIT2: updated and fixed codesandbox demo: https://codesandbox.io/s/oq66nmyjpz EDIT3: This is also leading me into refactoring the examples and tests: facebook/react#13991 (npm link is not working properly with React hooks) |
Hooks update (v6.1.0-beta.0) is ready, you can try the beta release with Please play with it a bit if you have some time. I don't expect to add any breaking changes, so don't be afraid to try it out. Thanks everyone for the help so far! |
@solkimicreb thank you for taking the time and implementing this! |
I'm seeing a difference in how batching works in React@next + Easy State@next comparing to [email protected] + EasyState@current. Not sure which one is caused that, but: export async function fetchModels([tableName, ids]) {
state.loading += 1 // !!! this previously caused components to rerender with <Loading/>
// !!! now it's batched, previous behavior was what I wanted
let apiUrl = `/api/${tableName}/id`
let reqResult = await fetchJSON(apiUrl, {
method: "SEARCH",
body: ids,
})
if (reqResult instanceof Error) {
return handleHttpError(apiUrl, reqResult)
} else {
let models = reqResult.models
batch(() => {
state.loading -= 1
state[tableName] = R.merge(state[tableName], models)
})
}
} Anyone experiencing the same? It there a way to disable this kind of batching? |
This were somehow caused by
No time to investigate, m.b. will help someone. |
Thanks for the catch, the second comment helped a lot! Which version of React Router are you using? |
Side note: this is (most probably) not a batching issue. In fact, you don't need to manually batch in your case. Auto batching was also improved in v.6.1.0, it covers pretty much all practical use cases. (Release notes coming with the stable update.) Batching manually has no drawbacks though, so if you don't mind the slightly ugly syntax you can keep them to be 100% sure. |
Tried with 4.3.0 and 4.4.beta
The initial reason to think "it's batching" for me was that only But as the change of composition order affects the behavior, it's probably not batching or not only batching – I agree on that. |
4.4.beta is using the new context api and I hoped it would eliminate this issue. I will add some React Router interaction tests and look into this before the next release. Thanks for the info again. |
@ivan-kleshnin Are you sure it was working with I am asking for a double check because I don't want to include accidental breaking changes. |
Yes, absolutely. Otherwise I wouldn't notice this change. I would estimate the probability that it was "something else affecting the impression" as extremely low in this case. Still it could be some weird combination of prop names, etc that made it work when it wouldn't for general case. |
Thanks! Did anyone else run into this issue with the beta? Edit: the issue is a change in behavior when used together with react-router |
Rechecked once again, and I see no problems with |
Hi @solkimicreb, I would love to try this out in my project and let you know how it works, but I need the latest bugfixes on master for my project to work. Whenever you have time, would it be possible to do a second beta release with the fixes from master 😄 |
Sure, I will try to do it soon. I was pretty busy recently. |
Hi all, the latest beta is out. You can try it with |
Thank you @solkimicreb! |
What are your vision of using
react-easy-state
with the new and fresh React Hooks?https://reactjs.org/docs/hooks-intro.html
The text was updated successfully, but these errors were encountered: