Bit of background: I'm trying to learn a React and am building a small app with next (using a template from a tutorial I did a while ago). I've recently run into an issue where I need to keep a timer in synch between 2 components that are not in the same hierarchical structure.
I have an Item component that displays a few details about that item(description, title, etc) in a more concise way (a tile displaying just part of the entire item info). If I click on the Item tile, i have a next.js Link component that looks like this:
<Link href={{pathname: "/item", query: { id: item.id }}}>
<a>{item.title}</a>
</Link>
which will redirect me to a new page containing an ItemDetails component which just displays all the information for that item in more detail and using the entire page instead of just the tile used for the Item.
As mentioned above, the issue is that I want to have a countdown timer that is kept in sync between Item and ItemDetails (can be started, stopped, etc from either of them and it's state would be reflected in the other component). Initially, I thought of using MobX and creating a store and using that as a way to keep the same state between the two components. However, the problem with that is that I have multiple instances of the Item component, each pointing to their own ItemDetails and by using a single store that would just share the state of the first started timer between all Items (might be wrong here though since MobX is something i just started reading about yesterday ^^).
My question is, what would be the best way to approach this issue? Is this doable using Mobx plus stores or is it an issue of how the app is structured (eg: find a way to make Item and ItemDetails part of the same hierarchical structure?
Any help would be appreciated.
Here's a working example using React "context" to share the data between components and refs to keep time across re-renders:
https://codesandbox.io/s/silly-http-h25dr?fontsize=14&hidenavigation=1&theme=dark
Related
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?
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.
I have an application with three main components. Form allows users to select items, Preview shows those items, AppStore is a Mobx store. The button seems to work fine, adding items to the store but the Preview component isn't re-rendering in response to changes. I think this might be because I'm using a higher order component for my drag and drop feature. Does anyone know anything about getting these to work with Mobx?
The project can be found here (the only buttons I've linked up at the moment are 'Banner Image' which adds an item and 'Remove' which should remove it): https://codesandbox.io/s/vnooqvn8yy
I think the issue is that SortableList needs to be passed a regular javascript array, not an observable array.
<SortableList items={AppStore.currentBlocks.slice()} onSortEnd={this.onSortEnd} />
From the mobx docs:
...whenever you need to pass an observable array to an external library, it is a good idea to create a shallow copy before passing it to other libraries or built-in functions (which is good practice anyway) by using array.slice()
I wrote a service in angular that fetches items from firebase using snapshotChanges and return them. than in my component i subscribe to the data and store theme in an array. than i show the data in cards using ngFor.
Everytime i switch pages (without reloading) the data is being reloaded in a visible way, it hurts the UX and doesn't look good. i tried using take(1) but it didn't work. Sometimes it shows the same data multiple times.
Why is this happening and what should i do to fix it ?
Tank you :)
You could try to load the data in a wrapper component and pass it to the children. This happens because a component (and all of the loaded data) is destroyed when the component is left and the route is changed.
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.