React.js call components into setState - javascript

I'm trying to make a toaster component.
https://codesandbox.io/s/62n81oy4pr
in index.js, this.setState({ toasterText: "Room added to summary." });
from this code, you can change the value of the toaster whatever you want and When you click the button several times, the toaster keeps showing and then disappear after 2.6 sec from the last click.
However, When I set a component (or even a div) into the 'toasterText' and click the button,
something like this,
this.setState({ toasterText: <Component>asdfasdf</Component> });
the toaster appear by one click and disappear as soon as I click the button again.
I think I can do something with the componentDidUpdate or am I just not allowed to set components in setState??
sorry for my bad English.

The reason it "disappears" is because the component is re-mounted (destroyed and re-created), as opposed to re-rendered (text updated) in your first example.
While it is technically possible to do this, it is considered anti-pattern for numerous reasons (the problem you experienced being one of them). I can't think of any reason you'd ever want to take that approach; just stick with updating the text.
If you really have to implement the second approach, try adding a key prop to the component. That should prevent the re-mounting behavior.

Related

Ternary statement causing react components to completely disappear briefly

Here is an example to reproduce: https://codesandbox.io/s/crazy-kirch-f7fso8?file=/src/App.js
To reproduce:
right click and inspect the elements.
In your inspector (assuming you have this capability), right click on the div with the wrapper id and break on subtree modifications.
Click toggle button
Click "resume script execution" arrow to jump through each subtree modification.
Notice how initially, neither imported component renders, then they pop back in on a subsequent render.
Walking through the example in a bit more detail:
I am conditionally rendering 3 types of thing depending on a single variable using the ternary operator.
String - this seems to update immediately
Element - this seems to update just after the string does
Imported component - both components disappear, then one comes back (after element and string).
Does anyone know what may be causing imported components to briefly disappear? This is causing a flash of content that I'd like to avoid.
That is because A and B are different components, so on each toggle, you need to unmount the rendered one and mount the other. This means removing the node from the DOM and then inserting the other one.
The other cases are treated as the same element with just a text content change. Not mounting/unmounting happening here.
About the flashing, i cannot reproduce on FF or Chrome. Only if i have the break-on-modifications enabled i see it.

Change detection doesn't happen in synchronous codes

I was working on a component that has a button which toggles a boolean. This boolean is supposed to determine if a child component in the HTML need to re-render or not, since I want the ngOnInit function in the child to be re-run.
The situation is described in the app component here: https://codesandbox.io/s/angular-qxtm8
The app.component is the parent and second.component is the child.
I have tried three different solutions. They are onTestClickOne, onTestClickTwo, and onTestClickThree in app.component.ts. onTestClickOne and onTestClickTwo successfully re-triggers the ngOnInit in the child component. We can see the console log in it is printed on the console whenever I click the corresponding buttons. However, onTestClickThree didn't work.
I'm not 100% sure why onTestClickThree didn't work, and onTestClickTwo did.
My guesses are the following:
onTestClickTwo works because the change detection in Angular is run after the event handler has been executed. So, it will detect the boolean has been set to true. After that, the event loop will get the callback of the setTimeout and put it into the stack. Angular will execute change detection after finishing the callback.
onTestClickThree didn't work because, by the time Angular runs change detection, the boolean is already true. Angular doesn't know that it has been changed.
Let's tackle the main issue there, which is your design : why would you re-render the component to trigger ngOnInit again ?
Sure, in the case of your example, that's no big deal. But what happens for a fully coded component, making http calls, having children and all ? That will cause some severe performance issues.
Instead of re-rendering the component, you should use a function to do that.
If the event (that is initially supposed to re-render the component) comes from the child, then use an #Output. If it comes from the parent, use a #ViewChild reference.
As you can see it works well, without any detection issue.

React Native navigation.goBack() inside componentDidUpdate

I am trying to call the navigation.goBack() inside componentDidUpdate, the backing works however the animation of going back does not. Like the slide effect.
The use case that I have is for implementing an edit screen. Suppose you just edited some items but now when you click update/save you want to go back. In order to catch that update/save event, I am making it a part of the NavigationScreenProp, this is setting the state of the NavigationScreenProp.
Once the header update button is clicked the NavigationScreenProp becomes {isUpdated=true}. This fires the componentDidUpdate event and inside of it I handle saving the data, however the problem occurs when calling the back.
This scenario however works if you create an alert when isUpdated===true and goes back with animation.
Any help or direction would be great help! Thanks!
Also if there is a better way to handle this scenario, please comment :)

React Native/Expo: Event Emitter between screens; trigger refresh

I've scoured this site and various Github issues for a solution but am still a bit stuck. In essence, this is the flow that I desire:
Land on first component/screen, which has some information
Click a button and be pushed to a second component/screen
Do something on this second component/screen
Pop back to first component/screen
Have refreshed information be displayed when we come back to this page
Issues:
Component lifecycles don't work because when I'm popping from the second component to the first component (the parent), there's no component lifecycle method I can call in this case.
Event Emitters won't suffice as a solution because they only work within a single component (is this correct btw?)
Would greatly appreciate any help I can get. Thank you!
In the first component, create a function that will refresh the component by updating the state. Pass the function to the second component and when you pop, call this function.

What constitutes an appropriate use of ref in React

Can someone explain how ref is used in React? I understand it's a shortcut that sort of defeats the purpose of the react DOM, but I don't know how or why exactly. I'm trying to determine whether something I'm trying to accomplish represents one of the rare cases where you should use ref
I want a custom bootstrap alert I can show from any of these pages, without using JQuery (I have one working with JQuery already)
I have a router that switches between pages, each containing a Layout component with a Page component inside (based on this)
Like:
render() {
return (<Layout ref={layout => (this.layout = layout)}>
<WhateverPage
session={this.session}
otherExampleProp={"something"}
showAlert={this.showAlert}/>
</Layout>);
}
showAlert(type, text, hasTimeout, timeoutMs) {
this.layout.alert.showAlert(type, text, hasTimeout, timeoutMs);
}
I can think of three solutions:
Use ref, which as I only partially understand defeats the purpose of react components to some extent, but I'm not sure how exactly...
Use ref, but to a lesser extent, by placing the alert component in each Layout before the Page component (so no need for a ref to ).
Create a component and a function on each page, using the page's state to control the alert, so it would be basically the same as creating a unique alert for each page, which also defeats the purpose of a component...
The example most people give when explaining what to use ref for involves focus() - is this similar? Intuitively it feels like I should use ref, but I also know that theoretically you shouldn't, but I want to understand why, because there are exceptions and for all I know this may count.
Similarly, I want to create a confirm component to replace the native JS confirm() (since it might be deprecated soon), and this approach (using ref) also makes this WAY easier than creating a component for each page, since I can pass any function as a parameter to the confirm component for it to execute on an OK button press (also gives me the option of including icons, titles, custom buttons, etc).
Existing examples and libraries all seem to use method 3 (or they're simpler, and not not really analogous).
Is ref ok to use here? Is it wrong? Why? Am I overthinking this?
Yes, you are "misusing" ref here because you're trying to build around how React is intended to be used.
ref is mainly for accessing the actual rendered DOM element - maybe to focus it, read input, get dimensions, whatever. Generally speaking though you should us ref as a "read only" feature - use it to get info about the rendered DOM but don't use it as part of a process to bypass render() or inject elements into the DOM.
What you should do is create a reusable component for your Alert. Make it flexible enough that it can accept arbitrary settings like color, text, duration, callback functions for accept/cancel/clear, etc. Then you can just render it somewhere, maybe like this:
<MyAlert
title="foo"
text="bar"
duration={5}
confirmCallback={someFunction}
cancelCallback={anotherFunction}
/>
Remember that components are a way to render and interact with state, and that's exactly what you're trying to do with your Alert. There is some kind of notification, it has content and controls for doing some action(s), and all of that should live somewhere in your app state hierarchy. There is absolutely no reason to resort to refin this situation.
To complement the jered answer:
If you plan to use the alert component in all the pages then instead of placing an alert component inside each page you can create a high order component named like PageWithAlert (I would say just Page) that includes the alert component for each page.
You might want to take a look at this https://facebook.github.io/react/docs/higher-order-components.html

Categories