I'm currently working on a single page dapp for lucky bunny farm, it all works and will be released soon. But i'm wondering if maybe i've engineered it entirely wrong because i have put most of the business logic within a collection of useEffects (6). Because i dont have any other pages on the site i've not created hooks as i would in other situations because there's no benefit from a writing code point of view.
It seems to me that having 6 useEffects working off the state variables i've set might be a little much, is there a performance gain from reducing them or doing something else? I have created components for the various on page assets and those internally have their own state and useEffect hooks too. What's the danger in a "large" number of these hooks and at what point should i consider optimising for performance.
Or am i over thinking this and actually this is quite normal and i should only worry when i have say 20 hooks all doing their own thing.
Additionally, i tend to use state for single variables instead of objects, is there a performance gain from using a single state with an object.
So to use an example i have the following states:
dappActionStarted
dappActionCompleted
dappActionError
Would it be more efficient to have something like:
{
started
completed
error
}
And then do a single useEffect for that object as opposed to the three i would need to manage 3 seperate state vars.
Related
I am currently upgrading react version from 16 to 17, and refactoring old code (changing class-components to functional components, use hooks, get rid of mobx).
There is currently a pattern in place, which I am not sure about:
Whenever there is a user-interaction, the respective state-change is done, by
Calling the Setter-Function of React.useState
Cloning the whole state-object with _.cloneDeep
Applying all the changes on the cloned-state-object
Returning the cloned-state-object
This pattern is nice, because within the Setter-Function of react, I can do as many state-updates I want; I even can pass this state-object to other functions (within the react-setter-function) which then apply additional state-updates if necessary;
I've not yet discovered any performance problems with that pattern, but I suspect, that I trigger a re-render of the whole page, whenever I replace the state-object with that cloned-object.
Should I change the pattern or stick to it?
I am writing a little "fun" Scala/Scala.js project.
On my server I have Entities which are referenced by uuid-s
(inside Ref-s).
For the sake of "fun", I don't want to use flux/redux architecture but still use React on the client (with ScalaJS-React).
What I am trying to do instead is to have a simple cache, for example:
when a React UserDisplayComponent wants the display the Entity User with uuid=0003
then the render() method calls to the Cache (which is passed in as a prop)
let's assume that this is the first time that the UserDisplayComponent asks for this particular User (with uuid=0003) and the Cache does not have it yet
then the Cache makes an AjaxCall to fetch the User from the server
when the AjaxCall returns the Cache triggers re-render
BUT ! now when the component is asking for the User from the Cache, it gets the User Entity from the Cache immediately and does not trigger an AjaxCall
The way I would like to implement this is the following :
I start a render()
"stuff" inside render() asks the Cache for all sorts of Entities
Cache returns either Loading or the Entity itself.
at the end of render the Cache sends all the AjaxRequest-s to the server and waits for all of them to return
once all AjaxRequests have returned (let's assume that they do - for the sake of simplicity) the Cache triggers a "re-render()" and now all entities that have been requested before are provided by the Cache right away.
of course it can happen that the newly arrived Entity-s will trigger the render() to fetch more Entity-s if for example I load an Entity that is for example case class UserList(ul: List[Ref[User]]) type. But let's not worry about this now.
QUESTIONS:
1) Am I doing something really wrong if I am doing the state handling this way ?
2) Is there an already existing solution for this ?
I looked around but everything was FLUX/REDUX etc... along these lines... - which I want to AVOID for the sake of :
"fun"
curiosity
exploration
playing around
I think this simple cache will be simpler for my use-case because I want to take the "REF" based "domain model" over to the client in a simple way: as if the client was on the server and the network would be infinitely fast and zero latency (this is what the cache would simulate).
Consider what issues you need to address to build a rich dynamic web UI, and what libraries / layers typically handle those issues for you.
1. DOM Events (clicks etc.) need to trigger changes in State
This is relatively easy. DOM nodes expose callback-based listener API that is straightforward to adapt to any architecture.
2. Changes in State need to trigger updates to DOM nodes
This is trickier because it needs to be done efficiently and in a maintainable manner. You don't want to re-render your whole component from scratch whenever its state changes, and you don't want to write tons of jquery-style spaghetti code to manually update the DOM as that would be too error prone even if efficient at runtime.
This problem is mainly why libraries like React exist, they abstract this away behind virtual DOM. But you can also abstract this away without virtual DOM, like my own Laminar library does.
Forgoing a library solution to this problem is only workable for simpler apps.
3. Components should be able to read / write Global State
This is the part that flux / redux solve. Specifically, these are issues #1 and #2 all over again, except as applied to global state as opposed to component state.
4. Caching
Caching is hard because cache needs to be invalidated at some point, on top of everything else above.
Flux / redux do not help with this at all. One of the libraries that does help is Relay, which works much like your proposed solution, except way more elaborate, and on top of React and GraphQL. Reading its documentation will help you with your problem. You can definitely implement a small subset of relay's functionality in plain Scala.js if you don't need the whole React / GraphQL baggage, but you need to know the prior art.
5. Serialization and type safety
This is the only issue on this list that relates to Scala.js as opposed to Javascript and SPAs in general.
Scala objects need to be serialized to travel over the network. Into JSON, protobufs, or whatever else, but you need a system for this that will not involve error-prone manual work. There are many Scala.js libraries that address this issue such as upickle, Autowire, endpoints, sloth, etc. Key words: "Scala JSON library", or "Scala type-safe RPC", depending on what kind of solution you want.
I hope these principles suffice as an answer. When you understand these issues, it should be obvious whether your solution will work for a given use case or not. As it is, you didn't describe how your solution addresses issues 2, 4, and 5. You can use some of the libraries I mentioned or implement your own solutions with similar ideas / algorithms.
On a minor technical note, consider implementing an async, Future-based API for your cache layer, so that it returns Future[Entity] instead of Loading | Entity.
I have at least two approaches to solve a problem.
Repreform calculations inside views on each update (map, filter, find)
Keep an "CurrentState" object inside my redux state.
I choose to create a CurrentState object that stores my calculated result (It calculates the results inside the reducer function).
Approach 2 saves processor calculations, but it feels dirty.
is it considered an antipatern to have a CurrentState object (updated from the reducer) inside the state?
Thank you in advance!
Not totally clear from your question - but I assume that you are talking about situation, that you can compute "result" from other data in your store and asking if storing it (redundantly) in store is good pattern.
Well, generally I would not recommend it as keeping redundant data in store can lead to inconsistent data bugs - if you forgot to keep your data in sync (e.g. when you or someone else working on the project would change one data and forget to change the order place).
The standard patter for this is usually to use selectors and memonization (see https://github.com/reactjs/reselect). The idea is to keep only normalized data in your store but to use selectors in your views. Selectors are responsible to "cache" (memonize) extensive computation. Another advantage of selectors is that it provides level of indirection for your application and you can easily evolve your state (as the project grows) without affecting your whole application. On the other hand for small and one time projects selectors can be just "another" boilerplate - but in general I recommend to use them.
This was a hard anti-pattern.
If you are reading this chances are you don't fully understand redux and I would like to recommend
https://github.com/leoasis/redux-immutable-state-invariant
I have a component (table) that contains many lines with data editing in them, with masks in the form of contenteditable, it is possible to select all fields and change all the lines at the same time.
On desktop it works pretty fast, but on iPhone 6 I have unreal lagging, with Safari hanging for 20 seconds for each action.
I completed the recommendations to improve performance from React: prevent reconciliation, pure components, etc ...
Are there ways to improve performance? Is it necessary for me to ponder a functionality change on a mobile device, in favor of performance?
You should override shouldComponentUpdate component life cycle method for every row of the table. Ideally for every cell in every row.
If you have a table and it gets a different props. What happens is that every nested component gets re-rendered. PureComponents might help but writing shouldComponentUpdate is the only way to really control when something gets re-rendered.
Also for really large data list there is a react-virtualized. Check it out. Its pretty cool.
It would be nice if you could post source code though.
Adding to above answer, you should use react-perf module to exactly validate if any change actually made a performance gain.
https://github.com/crysislinux/chrome-react-perf
use this extension to exactly see how many times, each component on your page actually rendered, when you did your problematic/slow user interaction
try reducing no. of renders of each component. Also reduce the no. of components rendering on each such interaction.
try minimising time taken by each component. You can sort by time and focus on the most expensive components. Avoid rendering components higher in heirarchy, first. To find the exact reason behind a component's rendering use following method.
Put componentWillUpdate lifecycle hook, temporarily, and diff previous and next props/states. With this you would get the exact prop culprit behind a rendering. Unneccessary prop change might be in following scenarios:
When prop is just a function which is changing because of 'bind' usage or arrow-function usage, which changes the function reference everytime, and with that, causing new renders, everytime.
There might be a prop being initialised with new Object() or {} notation, which is considered new object everytime and hence new rendering. This can be avoided by a const READ_ONLY_OBJECT = {} and using READ_ONLY_OBJECT everytime a variable needs initialization.
You might be unnecessarily mutating object-type props and doing diffs in componentWillRecieveProps.
There can be more reasons to where we dont want a render but it happens because of the ways react works. Just see that props dont change unnecessarily. Also, dont put unnecssary componentWillRecieveProps/shouldCompoentUpdate checks as it can impact performance negatively. Also when using these, use these as higher in heirarchy as possible.
Some techniques to use
try to avoid using react lifecycle hooks which run on each render.
try reducing any scripts runing on every render.
use componentWillReieveProps, but only if you gain, else point 1 can reduce gains also. Also, using this often can lead to non-maintainable code. Always validate the gains with react-perf tools, before making changes related to optimizations.
use throttling in chrome-dev-tools to create slow device enviroments, use javascript profiling to see which javascript methods took most time.
Try using redux with react, to manage state. Redux also has componentWillReieveProps thing implemented for connected components. So, using redux will help.
When using redux use an appropriate batching stategy. You can also use batch middleware in redux.
Also, similarly, in react try to do events in batched manner so as to reduce amount of time spent in react's renderings and diffing algorithms. Try clubing setStates in react or actions in redux to reduce react scripting time.
Always use appropriate throttling/debouncing techniques while implementing input controls, to get immediate response. You can also use uncontrolled components to have immediate response, if your business logic allows. Idea is to not to run any javascript when user is typing or interacting with your page in any way, else he would notice the jank in devices particularly bad in computing power.
Your action handlers should not be lengthy. If lengthy, try to do them in chunks, asynchronously, with redux-actions or with just promises.
There is more to this list, but the problem is, react as a framewaork is pretty easy to get to work, initially, but sooner or later, any medium sized react app will run into these performance problems, as react's diffing and rendering logic incurs a lot of performance penalties in bad devices, as soon as app grows in size, only option is to get react-performance tools, also, into the build process, asap. This will let you validate and measure your improvements.
I'm fairly new to react, and really enjoying it. In creating components, is there a good rule of thumb (or simple generalization) to consider when deciding if a component should manage it's own state or not.
As example (only as example), an input that gets different classes added based on state, like 'hover', or 'not empty'...
Would it be better to create a component that manages those states internally or just handle that wherever I'm rendering an input?
I know this question may be 'primarily opinion based', but I'm hoping to get a general feel for how to think about it.
Thanks in advance,
-Ted
This is a constant internal battle that you'll just decide on down the line and you're right that it's primarily opinion based (meaning no answer will be correct). However, I can share my own experience and the process I take to decide on how to split the logic of my components.
I think of these things:
How will having/not having that piece of logic affect unit tests? If the component would need too much setup to be tested, then I move some logic into it and away from a parent Container component.
How often will I reuse the component? If it's many many times, then I look at the types of Container components that would render it and, again, if it seems like too much boilerplate is needed, then move the logic.
Does the value change through its own behavior or based on outside queues? In your example of the hover, the behavior changes due to its own behavior so it feels like the className (a prop of itself) is reacting to the component itself.
Most importantly, do you benefit from removing the logic and placing it in the Container? If you think that other component could benefit from knowing the hover state of your input field, then you may want to put the logic in the container. Otherwise you're abstracting away too much.
Application state management libraries such as Redux will often suggest to use their libraries as little as possible and instead rely on internal state of the component. I mention this because as you figure out where to put your logic, you have to think that about the end goal, which is usually to create a web application, with multiple components working together. Abstract too little and you end up creating non-reusable components. Abstract too much and you have tons of boilerplate and configuration lying around that could be trimmed by using internal state.
Zeke has some absolutely great points. I'd just like to add my own guideline, which is:
If the behavior of the component is the same, no matter where it's used, and is not tied to the behavior of the app/environment at large, then state should be internal
otherwise, manage state elsewhere and pass in props