How to speed up contacts handling in react native when slow? - javascript

I have been working on putting together a module to allow a user to invite their friends to use an app. Code works without major issue, but since I have over 100 contacts in my phone, the speed is rather slow. Scrolling isn't a problem, and I can add a loader as the phone pulls the data. But I when I choose an element for highlight it takes a few seconds for the item to get checked. I'm curious if anyone has any tips for how to optimize?
My snack is below:
https://snack.expo.io/#fauslyfox110/testingreferrals
Main file: inviteScreenTwo.js

React will update the elements on screen whenever you make it change to your state. In your case, I suspect that the delay is due to React going through all the contact records your showing and updating them when you change the highlighting.
One way of dealing with this is to make sure that contacts that are off-screen aren't actually in the DOM. You would need to update your render method to place only contact records in the list that are actually visible. That way, React won't need to update as many elements. Please refer to the React docs to read more about this optimization.
Another way would be to override the lifecycle method shouldComponentUpdate for your record components, making sure that the only rerender when their highlighted status changes. This is called reconciliation avoidance. The method has the following signature:
shouldComponentUpdate(nextProps, nextState) {
}
By default, this method always returns true. You could change it to compare nextProps with this.props, checking that the highlighting has changed, and return true or false as appropriate. Read more about this optimization in the React docs.

Related

How should you ensure state update order in react?

I have a couple set states on providers that trigger a bunch of effects throughout my react app. They happen back to back in a hook. The second set state has some effects that it triggers that need make sure that the first hook fully propagated through the app. Currently the first one has not made all the required changes so some functionality triggered by the second causing weird behavior. How do you ensure that the second one only happens after the first is fully propagated?
setSomeStateValue(x);
setValueToTriggersEffectsThatRelyOnUpdatesFromTheOther(y);
Here are some thing I have done that work but have their issues:
1.) settimeout(...,0)
setSomeStateValue(x);
setTimeout(otherSetState,0);
This pushes the second one to a subsequent batch. I like this one because it doesn't involve adding extra code to watch other state variables that the code maybe shouldn't be concerned with, but it does seem a little black magicy and could possibly cause hard to debug issues.
2.) monitor the stuff i need set before calling the second set state
This one seems a little more readable but involves importing and watching things that might not make sense that they belong in the related code. Basically adding a useEffect that watches everything I need set before the second call happens. Also if something changes in regards to what is needed to have the second call ready then this code will have to change as well where as the first solution should not require an update.
Both of these work but have their fallbacks. I would like to refactor the second call to account for these issues but that would be too large of a refactor at this point too make it a feasible option. Is there a native way to ensure this or another strategy here that I am missing? And if not, which one of the above solutions is better?
In such situations where a setState is dependent on a previous setState or a specific state of the component, you can potentially do two things. First,
use the second argument of setState. Here, callback is only invoked once setState is done updating the state. Hence you can get the desired synchronous behaviour.
setState(updater, [callback])
Use componentDidUpdate lifecycle method ( For Hooks, it would be just another useEffect ). If you don't want to have complex setStates in your component, simply have an effect with a dependency on the needed state and do your operations there
React.useEffect(() => {
if( desired_state){
secondSetState()
},
[ desired_state ]
}

data being loaded does load until after the render

Working on an application that pulls the current user to use as the default user. Using React 16.
So I am having a problem that I can't seem to find the solution to, hopefully fresher eyes than mine might be able to see a way to handle this. But first a little React knowledge.
React works in components. When a component is called, it has a couple of stages that it goes through before actually displaying any code.
constructor - the component is initiated, any data/structures that the component needs are created here.
componentDidMount -- once the component is created, they this where the data that it needs is loaded. For example, if you needed to display a list of items, those items would be loaded here.
render - this is where the html is created for the component is built. This is what displays things in the browser.
Obviously there is a lot more going on under the covers than just this, but this is sufficient for illustration purposes.
So my problem is I need to default some input in the render to show data that is supposedly loaded in the componentDidMount. But that doesn't seem to be happening. Instead, the data that I need is being loaded after the render.
I feel that either I am not understanding correctly how React does these things, or I need to create some sort of delay to allow the data to load completely before the render.
Can someone help me, direct me to a resource that could help, or tell me what I am doing wrong?

Trigger state change of a React component from Chrome extension on a Facebook post

I'm doing a Chrome plugin for Facebook and I want to modify a post using external javascript. I can change the textContent of a span but the state is not changed and the Save button is not activated.
The html looks like that :
<div class="" data-block="true" data-editor="1477r" data-offset-key="a699d-0-0">
<div data-offset-key="a699d-0-0" class="_1mf _1mj">
<span data-offset-key="a699d-0-0">
<span data-text="true">test</span>
</span>
</div>
</div>
The component in React Developper Tools :
[
I profiled a change of the text and this is the result for a 6 ms timeline activating the save button.
There are ways to modify a React input but did not found ways for my problem :
https://github.com/facebook/react/issues/11488
https://github.com/facebook/react/issues/10135#issuecomment-314441175
How can you change a Facebook post and his state with external javascript?
What would you do?
That’s not possible, you can’t imperatively mutate a React element tree from outside the app. You’d have to declaratively render a tree, either by modifying Facebook’s frontend code (beware of legal ramifications) or implementing your own post UI.
While it's nearly impossible to change the state of React component from your plugin, nothing stops you from emulating user's input by sending keystrokes, mouse clicks etc. The only thing you need it to figure out - which DOM-element listens to these events (not necessary one of those 4 in you question).
About the possibility of direct state change: let's say the component you need to changes is a functional one. Then it has a form of
Component() {
const [state, setState] = useState(...)
...
setState(something)
...
}
so you need to somehow access the setState function of the component. But how? It's private to the function call. If you think that instead you can call the useState directly, then be aware that in another component it will return another setState. I have no idea what would happen if you'll call useState outside of a component, but surely it will not be able to guess which setState you want.
If you want you can check the source code of react-devtools to find out how you can dig out the state from the depths of React... but would you really want to try? And for what? The next time Facebook or React will be updated your code will definitely break.

Ember component leaking state

I'm new to Ember and have a leaking state problem. I have a carousel widget that displays one item at a time and allows the user to click previous/next to see each item.
Here's the simplified carousel's component:
<button {{action "nextItem"}}>Next</button>
{{carousel-item item=selectedItem}}
Clicking next changes the selectedItem property so the next item is shown.
What I've realized is that the carousel-item component isn't re-initialized every time I move to a previous/next item. The DOM is reused each time, and the component's properties are shared since it's all one instance, which means I can have leaking state.
The alternative I see is to render all the items initially, so each has its own instance:
{{#each items as |item|}}
{{carousel-item item=item}}
{{/each}}
and to hide all but the selected item using CSS. However, this option kind of feels like a jQuery hack -- seems like Ember would have a better way. And I'm only ever showing one item at a time, so I hate to have so many extra DOM nodes when I don't need them.
What is the recommended way to handle this kind of a UI, where you only need one item shown at a time but don't want to share state between items? I'd imagine I should have one instance of the carousel-item component per item, instead of sharing an instance across all of them. But it doesn't feel right to instantiate every single carousel-item at first either. And I can't imagine the Ember way is to worry too much about the DOM details myself (determining which one is shown/hidden based on a class and some CSS).
Firstly, whatever framework or library you are using, jQuery, ember, angular, react, they are just a pack of JS/HTML/CSS right? So you should think in it's way, there is no magic!
So of course 1 component will only create 1 instance. If you just changed it's property(item in your demo), it just changed the property of an instance, other properties of it will remain as it is and triggered re-render. You cannot expect more. You have to manually reset other properties.
And yes, rendering everything by {{each}} looks stupid, but think about it, how could you create a smooth carousel animation by render only one DOM? At least you need to render 3 (current, previous and next) right?
Since carousel is a common UI, I recommend you to check existing ember addons fist before you write by yourself: https://emberobserver.com/?query=carousel
If I understood your problem correctly, the willUpdate hook in Ember.Component class should help you out. I this hook you can clear up the attributes, remove DOM objects, or anything at all. This will be called each time the component is about to re-render itself.
A simple example is of form:
willUpdate() {
Ember.$(this.get('element')).empty();
},
This will clear the DOM on each re-render forcing it to redraw elements.
You can try out other hooks too and see which event will serve your need. All of them are very helpful and serve different purpose.

MWC: how to rerender on URL change

Heyo everyone,
story time - skip if you don't care
I'm just starting out with Meteor + Polymer using Synthesis by #aruntk and I'm very happy about the results and greatful for the time he's invested in this project. There's one issue I'm having though.
I've previously only changed a iron-pages object to change the content of my view. Putting that in a FlowRouter like FlowRouter.route("/", action: {ironpages.select("home");}); works just fine. However, my site is getting more complex and I want to rerender a whole section now. I'm being told to do it reactively which is (to my poor understanding) the preferred way of building Apps here.
tl;dr - skip to here if you don't care about stories
So what I did is just putting mwcLayout.render("test-layout",{"main":"yas-manual-page"}); in my Router action. However, I have to reload to make the changes visible which is not what I want.
the router action is being called when changing the URL
the mwcLayout.render() call works if I reload the page once in the initial building of the site
calling mwcLayout.render() again at a later point does not do anything
I've read up on the topic and people say it's a problem with single-page apps and not building it reactively and whatnot, but I have no idea how this is not reactive. It's reacting to the URL change.
Please, if you have a minute, share some insight with me, I'm really stuck. :slight_smile:
Have a wonderful day y'all!
disclaimer: it's a repost form the Meteor forums which suggests coming here instead.
This behavior is added as a feature of mwc layout to prevent multiple re rendering during each route change. Workarounds here are to create another mwc layout or to set third argument forceRender. From the mwc:layout docs
forceRender
In mwc:layout we dont re render the layout unless the new layout is not equal to the current layout or forceRender argument is set. This is to prevent unwanted rerendering while changing routes(even if you change a param/queryparam the route gets rerun so does the render function written inside FlowRouter action). forceRender comes in handy when you have to change the rendering while keeping the current layout.
...
<mwc-layout id="demo-landing">
<div region="header"></div>
<div region="main"></div>
</mwc-layout>
...
imports/startup/client/router.js
...
action:function(params,queryParams){
mwcLayout.render("demo-landing",{"main":"test-layout1","header":"test-header"});
}
...
Now if you try
mwcLayout.render("demo-landing",{"main":"test-layout2","header":"test-header"});
from console it wont work since layout is not changed and forceRender is not set.
This works->
mwcLayout.render("demo-landing",{"main":"test-layout","header":"test-header"},true);

Categories

Resources