I am creating a profile screen for user in my apps . I am using lightbox from React-Native-Navigation by wix to perform an edit profile . So , the user will click the touchableopacity and a lightbox will pop up and the user will enter the new information and save it . So, im wonder is it possible if i want to pass the textinput value from lightbox to the parent(profile.js) so that i can setstate in the profile.js ?
Yes this is possible. You will need to send the data as props to the parent. If you haven't done it before it might feel a bit tricky but you'll get there.
From the parent:
<LightboxComponent
userData={this.handleUserData(data)}
/>
handleUserData(data) {
/* Do something with the data here */
}
From the child:
To send the data you need to set an onChange event or similar on the input you want to capture, like this:
<input name="user-name" onChange={ (e) => this.props.userData(e.target.value) }
This will make the input data from the child get sent to the parent. Every change will trigger a re-render of the affected components.
If your app complains about not being able to setState correctly, then you need to bind this in the parents constructor like this:
this.handleUserData = this.handleUserData.bind(this);
I would also say pass the parent's function pointer to the child as props (as seen on the React site). Although some people opt for using an event emitter. I'm actually really curious about more developers' opinions on that.
Is derailing a thread on StackOverflow grounds for epic down voting?
Related
Say I am building an instant messaging with app with React (I'm not doing that exactly, but this is easier to explain). I have a sidebar with a list of conversations and, when you click one, it is shown on the right (similar to this). I don't want to mount each conversation component until the user clicks it, but I don't want to unmount it, just hide it, when they click on another conversation. How can I do this cleanly? There will never be more than about 30 chats for any user.
You can store the enabled conversations in an array that you use to show, and when you disable a conversation you can just add a hidden prop to it which you pass to the conversation and make it return null. This will make it not render anything but will not unmount it since you have not removed it from the array that handles the display of conversations.
example at: https://codesandbox.io/s/wispy-forest-59bqj
This is a bit hard to answer since you haven't posted the code.
But, theoretically, the best way to approach this problem is to transfer the data from your sidebar component and load it onto the right component on a per-user basis. You don't have to mount each "conversation component".
You can do this by with the boolean hidden property in your markup. React will render as usual and simply pass it along to the html, the browser will then simply not paint it.
const HideMe = ({ isHidden }) => (
<div hidden={isHidden}>
can you see me?
</div>
)
I made an example for you:
https://codesandbox.io/s/elastic-curie-t4ill?file=/src/App.js
reference: https://www.w3schools.com/tags/att_hidden.asp
I have a React application using Material UI with a component (which we can call DatePicker) shown below, sneakily changed for demo purposes.
Material UI animates clicks and other interactions with its components. When clicking a radio button that has already been selected, or a "time button" which doesn't change state, this animation is visible above. However, when such a click changes the state, the animation get interrupted.
I can see why this happens from a technical perspective; the DatePicker component calls setMinutes, which is a property passed in from its parent (where the state lives). This is a React.useState variable, which then updates its corresponding minutes variable. Minutes is then passed into DatePicker, which re-renders due to a prop change.
If state lived within DatePicker then this problem shouldn't rear its head; however, DatePicker is one part of a much larger form which dictates the contents of a table in the parent. To generate rows for this table, the parent must have this information.
Below is a sample reconstruction of the parent:
const Parent = () => {
const [minutes, setMinutes] = React.useState(15);
const [radioOption, setRadioOption] = React.useState('Thank You');
// Many other state variables here to hold other filter information
return (<div>
<DatePicker minutes={minutes} setMinutes={setMinutes} radioOption={radioOption} setRadioOption={setRadioOption}/>
</div>);
};
And here a sample reconstruction of DatePicker:
const DatePicker: React.FC<DatePickerProps> = props => {
const {minutes, setMinutes, radioOption, setRadioOption} = props;
return (<div>
<Radios value={radioOption} onChange={val => setRadioOption(val)}/>
<Minutes value={minutes} onChange{val => setMinutes(val)}/>
</div>);
};
I'm not sure what the best practice is in this situation, but I get the distinct feeling that this is not it. Does anyone have any advice? Thanks in advance!
Thank you for your comment, Ryan Cogswell. I did create a code sandbox, and found that the problem was not about React state management as much as what I was doing beyond what I provided in my question.
I was using the withStyles HOC to wrap my component, in a way similar to const StyledDatePicker = withStyles(styles)(DatePicker). I then used that styled element and put properties (minutes, etc) on that.
It turns out that using the unstyled DatePicker resolves this issue. I troubleshooted this further, and found that I had created the "Styled" component within the "render" method of the parent, meaning every time a prop change was pushed up the chain, the parent would re-render and the entire "Styled" component type would be created again (or so I believe). This would break reference integrity, which explains the "drop and recreate" behaviour.
This teaches the valuable lesson of keeping components small and using code sandboxes for troubleshooting. Thanks again!
For anyone interested, here is the Code Sandbox used for testing.
I'm new ot react native and am having a hard time with the idea of not using inheritance, but rather composition.
My scenario: I'm creating a component (focusedTextInput) which shows one InputText. My component simply adds functionality to change the style of the TextInput on focus.
I'm using FocusedTextInput in another component which contains five focusedTextInput and I configure those to only have one character at a time and to auto-skip to the next FocusedTextInput when the character is entered (using the focus() method).
Where I'm running into issues is the my FocusedTextInput does not have a focus method (and I don't want to expose the TextInput).
So do I need to surface all the method that might be used from TextInput on FocusedTextInput or is there a better way?
See this answer React set focus on input after render on stack overflow.
I think this applies to react-native but it does work in the web.
That shows you how to set a ref to a component. And in the CDM set the focus to that component.
To extend how that works so you can set the focus to a specific input (if there are many) is to add a prop called setFocused
Change the CDM to
// Set the focus on first render.
componentDidMount(){
if (this.props.setFocus) {
this.nameInput.focus();
}
}
// focus if the prop changes
componentWillRecieveProps(nextProps) {
if (this.nextProps.setFocus) {
this.nameInput.focus();
}
}
I'm running into a weird case that only seems to happen upon first loading a component on a heavily based component page (loading 30+ components).
#Component{
selector: <parent-component>
template: `<child-component [myObject]=myObject>
}
export class ParentComponent {
private myObject:DTOValue;
constructor(service:MyService){
service.getDTOValue().subscribe((dtoValue:DTOValue) => {
this.myObject = dtoValue;
});
}
}
#Component{
selector: <child-component>
template: `<div></div>
}
export class ChildComponent {
#Input set myObject(value:DTOValue) => {//do something};
constructor(){
}
}
In this code, the Parent is going to get a value to a child as an input. This value comes from a request at a later time, so when the child is first initialized, the input could be undefined. When the value does get returned from the request and is set on the variable myObject, I'd expect that the child component would receive an input event being triggered. However, due to the timing, it seems like this is not always the case, especially when I first load a page that contains a lot of files being loaded.
In the case that the child component doesn't receive the input, if I click else where on my page, it seems to now trigger the change detection and will get the input value.
The 2 possible solutions I can think of that would require some large code changes so I want to make sure I choose the right now before implement them.
Change the input to be an Subject, so that I push the input value which should ensure that a correct event is triggered(this seems like overkill).
Use the dynamic loader to load the component when the request as return with the correct value (also seems like overkill).
UPDATE:
Adding a plnker: http://plnkr.co/edit/1bUelmPFjwPDjUBDC4vb, you can see in here that the title seems to never get its data bindings applied.
Any suggestions would be appreciated.
Thanks!
If you can identify where the problem is and appropriate lifecycle hook where you could solve it, you can let Angular know using ChangeDetectorRef.
constructor(private _ref: ChangeDetectorRef)
method_where_changes_are_overlooked() {
do_something();
// tell angular to force change detection
this._ref.markForCheck();
}
I had a similar issue, only with router - it needed to do redirect when/if API server goes offline. I solved it by marking routerOnActivate() for check...
When you trigger change detection this way a "branch" of a component tree is marked for change detection, from this component to the app root. You can watch this talk by Victor Savkin about this subject...
Apologize, the issue ended up being my interaction with jQuery. When I triggered an event for a component to be loaded, inside of the jQuery code, it wouldn't trigger the life cycle. The fix was after the code was loaded to then call for a change detection.
I've got an OAuth process that pops up a window, but when I log in, the redirect to the OAuth callback page happens within the popup rather than the parent window (window.opener). This might be a bit hacky, but I'd like a way for the popup window to tell the parent "we're authorized!"
This actually works:
OAuthCallback = React.createClass({
displayName: 'OAuthCallback',
render() {
window.opener.console.log('hello parent window');
return (
<div>
Hi, OAuth is process is done.
</div>
)
}
});
But I'm wondering if there's some way I can have the popup window tell the parent window to call a prop function, e.g. this.props.oauthSucceeded().
When you are unable to establish any parent-child or sibling relationship between the components, React recommends setting up an event system.
For communication between two components that don't have a
parent-child relationship, you can set up your own global event
system. Subscribe to events in componentDidMount(), unsubscribe in
componentWillUnmount(), and call setState() when you receive an event.
Flux pattern is one of the possible ways to arrange this.
see https://facebook.github.io/react/tips/communicate-between-components.html
Have a look at window.postMessage for cross window communication (https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)
Eelke's suggestion was spot on.
I used window.postMessage() in the child window, then window.close(), then added a window.addEventListener('message', function(){}) in the componentDidMount method of of main/master component.
Check out https://facebook.github.io/react/tips/dom-event-listeners.html for more information!
I had a unique situation where I had to work on an iframed react popup from an asp.net application. I had to provide a x button to close the popup by calling a closePopup method in the parent asp.net in addition to other ways to close it. I used window.parent. Below is how I used it.
if (window && window.parent) {
window.parent.closePopup();
}