Using https://github.com/reactjs/express-react-views as a starting point, I can successfully get server-side rendering/client-side mounting working. Problem I have is the size of the page once react has stamped data-reactid's over the state passed to renderComponentToString.
The object itself is a JSON payload from a server-side async call and comes in around 80KB. I pass this as is to renderComponentToString and the resultant page is over 20MB!
At this stage I'm thinking I could switch to renderComponentToStaticMarkup and take the hit client side for the first diff when I next update the state but wondering if there is a smarter solution here (props vs state?). Looking at the very clever react-quickstart (https://github.com/andreypopp/react-quickstart) I see the async state is effectively completely decoupled from the normal component lifecycle and therefore doesn't suffer from this issue however there's a lot of moving parts here and I'd rather come up with something more lightweight based on https://github.com/reactjs/express-react-views but with the necessary moving parts in place for client-side mounting to work.
Thoughts? Am I doing something wrong here?
I've resolved this for now:
The serialised payload for client-side mount was actually being rendered in the react render method, which was a noob error on my part. This was done rather than stringifying it and passing it down in a piece of non-react markup, which is what I should have done from the start.
Related
It seems to me the trend is replacing Redux with React Context API and useReducer.
I personally do not like a huge store at root with states from user data to if a dialog is opened all mixed together.
Switching to React Context API allowed me to push the state down and closer to where they will be used. However I can only push it down to the level that child components are either displaying or modifying that value. For example:
<Parent>
<CounterDisplay/>
<CounterIncreaseButton/>
</Parent>
I have to have count on Parent and create a Context. Within the Context, I'll add the count value and an increaseCount method (or a state and a dispatch function when use reducer pattern). Then I provide the context to those 2 child components. Now one can display it and one can modify it.
Now what if I need another button located far from this part of the component tree that also need to change the count value? I have to lift the state up and maybe all the way to the root. That feels strange to me.
2nd issue is when states are scattered at multiple level along the path in the tree, when something happens say user click a button, you may need to call multiple functions from multiple contexts (or dispatch multiple actions, one for each state that may or may not change). Unlike when use Redux since everything is at the root, you just need to dispatch one action.
So what if instead I have an event pub/sub at the root level? I can have the counter state and code manipulate it pushed down even more to CounterDisplay. CounterDisplay need to subscribe to the pub/sub system and listen to the event and update counter correspondingly. And whichever component want to change the counter can just raise an event.
What am I missing in this pattern? Circular event loop? Raise conditions? Feels a good pub/sub library can prevent these. I looked around and did not find something existing. I looked at RxJS but don't feel that fits.
Thanks in advance for sharing your thoughts.
You've basically just described the exact reason for Redux to exist :)
Redux is "an event pub/sub at the root level", and can specifically be beneficial in cases where widely separated components need to make use of the same data.
You may want to read my post Redux - Not Dead Yet!, which describes how Redux fits into today's ecosystem (including comparisons vs context) and some of the reasons you might find it useful.
If you are put off redux by the amount of boilerplate.
I would suggest taking a look at redux-zero.
Under the hood. react-redux uses a context provider at the root.
When you use the connect Higher-Order-Component that is using the context.
Same with the redux hooks.
So it's quite normal to have the provider at the very top.
It would be the same for any library like the react-router to do the same.
I would suggest you keep trying without redux so you can learn more. Put the provider at the root. It won't impact performance in anyway.
Isolate the context you create and the provider to a singleton file and import it to the components you need
You are right that there are too much words. The only remaining question now is:
Why is it considered to be normal to fetch data in cDM method if it is called after rendering and will cause an extra re-rendering and re-drawing after data has been fetched? More to it - user will see screen flickering.
I've spent two hours reading SO and other articles and still have questions. I'd like to get a better grasp of things and reassure them that my understanding is correct.
It all started with learning hooks and thinking about the difference between useEffect and useLayoutEffect. I learnt that useEffect should be used when things which it does don't affect what is shown to user (some background job) and useLayoutEffect is fired "synchronously before painting" - so, for example, should be used when I want to show a list on screen and data for it is fetched form somewhere else. Thus, if I fetch data in useLayoutEffect it will fetch the data first, and only after that update state and show the screen with that data to the user. If I used useEffect it would show to the user an empty list first (because it is asynchronous and doesn't stop painting) and then re-paint it after data is received. Confusing part is that it says that useLayoutEffect, the same as useEffect, is called after the rendering has finished. I explain why it doesn't make any sense to me in the last paragraph.
Another confusing thing is that it says that useEffect should be used in the same place where cDM or cDU methods are called. But I've been fetching data in cDM method since I started using react.
Does it mean that I did it wrong all the time? Because I should have done it where useLayoutEffect is fired. And this brings me to the next paragraph.
The most confusing thing - a relationship between rendering, painting and cDM method. It says that cDM is called after the rendering has finished. It also says that "rendering has finished" means that DOM, layout, sizes, styles - everything is calculated and ready to be painted by the browser. I understand it in a way that at this point it makes no sense to do anything that would change what is shown to a user - because it is all already calculated! Shouldn't there be a hook that is called before rendering? For example, I call this hook to fetch data for some list which is shown on screen. Only after data is fetched rendering should occur because now react knows how many elements are on the list and how much space will it take and so on. I mean what's a point in making rendering before you know all your data? Isn't react forced to recalculate everything after data is fetched?
I really hope you will help me to understand these things. Thank you.
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 new to React and trying to get how to build a good app architecture with it.
I also use typescript with all that features: interfaces, async-await, generics, etc. So, I'm puzzled about implementing some patterns:
1) Dependency Injection and reusable component instances
The first thing I can't get through is DI. Let's say we got a component class UserProfile that requires some dependencies like UserProvider. It would be perfect if the component instance (with deps injected) could be reusable, but I'm afraid it's only my dreams, not the react guys'. :)
So, I'm supposed to place this component this way:
<UserProfile id={123} />
Ok, what's the proper way to inject the dependency here? As an attribute like this <UserProfile id={123} dependency={userProvider: userProviderInstance} />?
Don't you think it is weird to put component input data, options/parameters and dependencies all together? I'd be happy if I could clearly separate them and put generic restrictions on the component class. What's the best practice?
Another side of impossibility to reuse component instances is the fact we must carry some needless objects through all the components structure just to inject them somewhere deep at the bottom. And nobody tells you what component does really use them. And try to imagine what adding a dependency to a low-level component will take in a large project. I just can't.
2) Using Promises
Let's consider a simple component that is supposed to render a counter: <Counter value={123} />.
Now, value is got from some API by calling a method getCounter(id: number): Promise<number>;, so the obvious way to put all together could look like this:
<Counter value={await provider.getCounter(id)} />
But i't impossible, I know. The common practice tells us to make it through setState method and rerender the component after the value is received.
Now imagine that the parent component is pretty complex and has many different providers. So, the parent component may not have definite state typing. It also may be conditional, you know...
You could suggest me implement the async getting in the Counter component, but i will refuse for a simple reason: That component does not know anything about the value's origin. In other cases the value is passed directly as a number. So, do you got better ideas how to keep code clean and simple while using promises?
Please, let me know if you come across some good articles or have your own experience in solving these issues.
PS: Thanks for attention! :)
This topic is a subject of bias - so below I will give my very personal thoughts on the topic that does not pretend to be absolute truth.
DI.
This is indeed not so common pattern in react as it is in angular. But having both context and properties in components allows you to archive the same level of separation as with pure DI. Check the context - it will help you to get rid of passing same props through the whole component tree. There are quite a few articles on this topic already (one, two) - check them out. Also you might be interested in reading this thread).
Promises
I do not really see any problem here. React has a simple concept - basically you have state and based on this state your app can render itself. Whereas rendering is not async operation - the preparation/update of the state can easily be done asynchronously and after results are assigned to the corresponding parts of the state - the necessary child components will be updated automatically. If you component has no knowledge of how to obtain value - it should not try to do it in first place - value should be passed down as props.
For my client I'm creating something like quiz web app in react with redux based on websockets (socket.io) with a huge, very unique data. No user interaction, just presentation layer. It works like this: I get websocket event with url to my layout and payload data, and then I render given url and fire redux action with data as argument, which becomes app's state. Simple as that. BUT I noticed that on first render initial state is loading, not given from websocket as argument to action. As I said data I get is huge and unique so I didn't want declare in reducer something like this:
pageData: {
assets: [],
questions: [],
details: []
And so on. It's much more complicated btw it's just an example. Instead of this I made something like this:
pageData: {}
And I was hoping that on view (using connect) I can get this data like this:
this.props.view.pageData.questions
But then it turned out that I can not get this because it's undefined on first render. So my questions are:
Is there a way to access to this data on first render without
declaring whole structure?
If not, should I reconstruct given data in reducer?
Should I then create reducers for each page (there are like over 20 views
with unique data)
Of course I can declare everything in reducers but I feel it's very hard to maintain so much data.
But you know, maybe I'm just too lazy and I should declare initial state for each page and this question does not have sense ;).
I think you may have a few options here:
Define fallback data in your components if undefined
Don't render your page (or components) until you have received the data
Define your initialState explicitly as you already suggested
All or most your components expect or should expect data of a certain kind and in a certain format. For this reason, laying out the structure beforehand (#3) seems to be most appropriate. Ask yourself this: would my app still display correctly if the format of the web socket event data changes?
To answer your questions specifically:
Is there a way to access to this data on first render without
declaring whole structure?
Yes, you could use the || operator in your bindings to fall back (#1) to an empty array or object or value. Example <MyComponent listOfItems={this.props.items || []}. This effectively creates an empty state, however, IMO this should be standardized in the reducer/store with initialState.
Should I then create reducers for each page[?]
Not necessarily a reducer for each page, but a store with all pertinent data to your application. It is hard to say for sure without knowing more about the architecture of your app, but keeping small, well defined chunks of information is generally easier than one big blob.
I strongly advocate defining your data beforehand. It might sound cumbersome at first, but it will pay off greatly and helps others understand what the app might look like with live data.
that's because you haven't added default case in reducer
default:
return state;