I'm making a chat interface in ReactJS, and each item in the chat log displays the same avatar icon over and over again. Currently the problem I'm facing is that when new items are added the chat log, this image blinks in every list item, which does not look very presentable.
I want to know if there is a way to reuse the Component (most probably not) or the bitmap data, so that once loaded in memory, it can be shown more quickly without a perceivable blink. I have tried using data URL, but not to much avail.
Per request in comments further details:
I have a separate Component to show each chat log item. It contains an Image component to show the avatar.
On the top log I'm using a FlatList and in the renderItem I'm rendering the said chat log component. Whenever any message is sent or received it is appended to the array that the data in the FlatList is pointing to.
Whenever an item is added the list gets re-rendered causing the Image to be created again (I have searched but haven't found any good away of appending items to a FlatList without affecting existing children). Therefore I believe the solution lies in making the image load faster so that the re-render is not so perceivable.
One reason I think of the flickering is if you reassign the key of list items and forcing it to re-render. Check if there is any such case. Thats one of the main reasons component to re-render on listviews.
Related
I am working on an app that has a range of routes that display essentially the same data except the route filters the list based on a status property that determines which entries we want shown in the list.
So in my App.js file I have all the routes set up and the listItems are passed into each of these route components as a property. These items are then rendered out as a table.
Now I have some logic that greys the list out and disabled the buttons on the list items when the list is refreshing using a toggle (isRefreshing) state variable.
The isRefreshing state variable is toggled off using a useEffect() that fires when listItems is updated.
This works great for the refreshing button, but not so well when the route changes.
I've figured out it's because when the route changes the existing listItems prop gets fed into the new rendered list component it see that as listItems changing, so the useEffect() fires, toggling isRefreshing off.
2 seconds later the real data for this new route turns up in the list.
So my question is how can I prevent this from happening? I feel like I might have backed myself into a corner and made a serious architectural error.
Can anyone point me in the right direction?
I've created an example here:
https://codesandbox.io/s/small-sound-rikxv?file=/src/App.js:0-2353
As you can see the refresh button works as expected, but the route change causes the listItems prop to immediately cause my refresh indicator to stop, so you can see a console.log fired immediately after hitting the "list2" link, then 5 seconds later when the real data loads it fires again. The problem is that the initial prop value causes my refresh to stop.
Regards, John.
So I found that if I lifted the "refreshing" state variable right up to the same component the data fetching was happening in then things got a lot easier for me.
Even though the property value changes twice still, because the refreshing state is being handled further up the tree, with refreshing now getting passed down, it's not an issue.
With refreshing getting managed up the tree, the refreshing toggle only gets toggled when refreshing is actually happening and not when the prop thinks it has changed.
Thanks for getting me to code out a simple example, that really helped me conceptualize what was happening free from the clutter of my app's code base.
If there is no mistake:
React-Router's <Link/> component can carry over data (state) when the user doesn't leave the current tab or you force the user to open new tab on left click using target="_blank". Otherwise the state you send with it is lost because we'll have a new empty history stack.
localStorage can be used to share state between tabs but it's problematic in scenarios where i just want to store the data for only the regarding tab user is expected to navigate.
e.g. I want to set a state using the state/data I've stored for that specific tab and doesn't want to store it anymore/ forget about it. In this case, synchronization problems may occur when the user actually creates multiple tabs using the same <Link/> component but doesn't navigate to all of them. How?
Say, I've removed the state item from the storage when the component is unmounted in one of the tabs user is already navigated and, later on the user is navigated to another tab expecting the item in the storage to set the state. (The component in this tab will try to set state with non-existent data / will crash.)
I could hold the state till the window's onunload event is fired at best, but the problem still exists because localStorage is shared across all of the tabs and removing an item affects all the tabs like i've mentioned. ~ I have to remove the items somehow, can't rely on storage of 2MB to 10MB forever. I tried to find other solutions like clearing it once in a while on user logout/login but that would force the user to take those actions again, once in a while.
So I want to be able to store selected the state/data on sessionStorage of the newly instantiated tab and it gets cleared for me when that tab is closed and I don't have to deal with the regarding problems.
The problem could be defined with simpler words as:
I want to send a piece of data from one tab to another with empty history stack in the scope of only that tab.
Because I don't need it anywhere else.
I can do things like setState using that data, remove that data etc. and the other tabs launched in need of that data don't get affected.
I've searched through the other questions but there are not detailed answers covering this scenario or I couldn't come across with a best practice for this kind of stuff using ReactJS. Sorry If this is a duplicate.
I've got an app that shows a list of items in a grid. Some of the items have an embedded video which flashes or stops playing (if it's already playing) when it's rerendered.
The list is maintained in Redux. When the user scrolls to the bottom of the page it loads more results which causes the Redux state to update which, in turn, causes the grid to rerender all of the items plus the new items.
I'm looking for a solution that will just add more items to the end of the grid instead of rerendering everything.
I've got a component that holds the entire grid. It renders a component for each item in the grid. In each item I have a component that holds the embedded video.
Any ideas?
If each item in the grid is a component, like you said, you should use React.memo (for functional compoents) or Reat.PureComponent (for class components). It will prevent the component from rerendering if the props have not changed. I can't guarantee your videos will keep playing, but if the only reason they stop playing or flash is because the component is being rerendered then it should fix the problem.
Maybe this can help: when passing information from redux to your component, try to update the list of the objects instead of sending a new one
It's redux UpdateObject method.
I used react-infinite-scroll-component it's working just fine.
However, I want to avoid making the user lose his scroll position when he leaves the page and clicks back?
Also please put on consideration Firefox and Safari.
Not 100% sure because I haven't used it - but since no one else has chimed in... the docs say the component has a prop named key that is described as:
the key for the current data set being shown, used when the same
component can show different data sets at different times,
default=undefined
Also, it has a prop named onScroll that is described as:
a function that will listen to the scroll event on the scrolling
container. Note that the scroll event is throttled, so you may not
receive as many events as you would expect.
... which I suspect one of the arguments of which will tell you which keys it loaded / scrolled through.
So my approach would be to use componentWillUnmount to save the last key it loaded into a parent property (or Redux store if you're using Redux)... and when the component loads, if the key exists in the parent (or Redux store if you're using Redux) then pass it that key.
I am learning to react native and I found the following term on this documentation.
If you have a long list of more items that can fit on the screen, you should use a FlatList instead.
Which means that the FlatList component is used for a flat list that is fit on the screen and not scrollable. But on the FlatList documentation it says:
The FlatList component displays a scrolling list of changing, but similarly structured, data.
Please, can anyone tell what does it mean? Because both documentations are going opposite.
There is a lapse in your understanding of the sentence from the first documentation link. It actually says:
If you have a long list of more items than can fit on the screen, you should use a FlatList instead.
Notice that it says than instead of that which are totally opposite of each other. The phrase than can fit on the screen means that you have items that cannot fit within the current display size, so using FlatList is recommended.
Both ScrollView and FlatList are scrollable components. Some differences are:
ScrollView is a lot more generic. You can nest any sort of component within a ScrollView and they won't complain. FlatList on the other hand accepts similarly-structured data.
Components contained within a ScrollView will render together when it loads. FlatList will only render its children which are within the scope of the screen, and render the remaining ones when user scrolls to them.
UPDATE:
When I say 'display', I mean the phone's actual, physical display, and by 'container' I mean the set of components/items which make up your app's current page, like a combination of text inputs, buttons, views, etc.
Consider the following Log In form (source):
Every item (component) in this container screen is visible on the phone's display since there aren't a lot of components to begin with. You can get away without using the support for scroll here.
However there a lot of times when you have a lot of components in your container but the display can only fit a limited number of them at a time. Rest of the components would, sort of, spill out of the phone's display. In those cases, you must use a scrollable component to properly display all of them, and so that your app's user can actually reach the components which are out of display's current range. For example an inbox with many messages, or a to-do list with many items:
In the image above, phone's display can only show first 6 items in the inbox. What about the rest of them? Of course you have to scroll to see them! You may use ScrollView or a FlatList to enable the support for scrolling here.
Now, if you use ScrollView in these cases, all children (inbox items) within the container will load when this particular app page loads, i.e. at the same time. Consider an inbox with 3000 items. It would take forever to load all of them at the same time! The user would be waiting for a long time for them to load. Therefore, a simple ScrollView won't work here.
Fortunately, we have FlatList for that.
When you use FlatList to display scrollable components, only a limited number of items will render at a time which can fit the current display (say, 6 items in the example above). What about the remaining 2994 items? FlatList will render them dynamically as the user keeps scrolling down.