This is more of a performance/best practice question.
I currently have a child component that needs to alter state of it's parent and run an AJAX request on the parent. When the TouchableHighlight is pressed, the child scene needs to change back and the parent state needs to change/execute ajax request.
I'm using React Native Router Flux for my navigation.
Is the best way to accomplish this to pass the needed state changes through props back to the parent e.g. Actions.feed({foo:bar}) ?
Or can I pass a parent method through to the child via props and execute that from the child? That method would update the parents state.
The problem I'm having with that approach is that I cannot alter the parent state and change scenes at the same time as the parent is still mounting and you cannot setState on a mounting component. Is there someway to do this with a Promise from the parent method that can be returned once the setState has completed at which point I can change Scene? Not sure how to do this or even if it's the best method.
Any help would be appreciated.
The general practice is to provide a callback to the child component. For ex:
export default class Child extends Component{
render(){
return (<TouchableHighlight onPress={this.props.onItemClicked}>
....
</TouchableHighlight>);
}
export default class Parent extends Component{
.....
onItemClicked(){
//ajax request, set state
}
}
An improvement over this would be fire off a Flux action. You can do that in the child component if you don't intend to make it reusable or if you want it to be reusable fire off flux action in the parent component callback.
Related
I have a React table component that gets its data via a prop called TableStore. This prop is a high-level abstraction for getting row data:
interface TableStore<RowType> {
getRowIds: () => Array<RowId>;
getRow: (rowId: RowId) => RowType | undefined;
}
interface MaterialTableProps<RowType> {
tableStore: TableStore<RowType>;
}
function MaterialTable<RowType>(props: MaterialTableProps<RowType>) {
...
}
As you can see MaterialTable is not a MobX observer. It is part of a component library that is not dependent on MobX.
When I use this component in my app, I supply it a MobX-based TableStore. I would like the table component to re-render whenever the MobX-based store changes:
<MaterialTable tableStore={orderStore} />
However that does not happen because the table component is not a MobX observer. Is there any way to force the table component to re-render? For example, I am able to force a re-render by dereferencing the store in the parent component (using a simple console.log()). But this feels like a hack. Is there a better way?
Answering my own question....
I looked at several options but all of them were kludgy. I finally decided to rework the props of the table component to pass in an array instead of an abstract TableStore interface (which the table component can't react to). This allowed me to refrain from adding MobX as a dependency to the table component library while still leverage MobX in the parent component. In summary, the parent component now watches the MobX store, reacts to changes by creating a new array and passing it to the table component.
Here's the new interface for the table component:
export interface MaterialTableProps<T extends Entity> extends TableProps {
entityList: Array<T>;
}
export function MaterialTable<T extends Entity>(props: MaterialTableProps<T>) {
...
}
I have read this answer, but I want to change the structur of code a little bit,
actually I want to set parent state from child component but i don't want to add any function in parent component
actually the expected result looks like :
class Parent extends React.Component {
constructor(props) {
super(props)
this.state={modalVisible:false}
}
render() {
return (
<Child modalVisible={this.state.modalVisible} />
<Button onClick={()=>this.setState({modalVisible:true})/>
)
}
}
class Child extends React.Component {
handler(e) {
//handle parent moadlVisible state to false again
}
render() {
return
<Modal
modalVisible = {this.props.modalVisible}>
<Button title="Close Modal" onPress={()=>this.handler(e)}/>
</Modal>
}
}
so I want to make it easy to call the child component without add some function in parent to handle the child component itself, even for closing the modal of child component
Is there a way to achieve what I want?
If you don't want any connection between the 2 components at all, then you may have to use a global state store, such as redux.
Docs can be found here:
https://redux.js.org/introduction
Redux creates a global state instead of local state between all of the components. It does require a little configuration but once you have it fully integrated, you can handle your scenario. Also as your components grow, it'll be easier to keep track of state.
Why can't I just use events?
Quote in a question here..
react.js custom events for communicating with parent nodes
The React way would be to pass callbacks down to children explicitly
via props — . There's no support for custom events w/ bubbling in
React.
The reactive programming abstraction is orthogonal:
Programming interactive systems by means of the observer pattern is
hard and error-prone yet is still the implementation standard in many
production environments. We present an approach to gradually deprecate
observers in favor of reactive programming abstractions. Several
library layers help programmers to smoothly migrate existing code from
callbacks to a more declarative programming model.
A horrid way to do it in my eyes would possibly be to use Async Storage
to store the key value, but I'm not going to suggest that.
I have split up the components only for the reason the base or the parent component code is growing in size and for code organization. so split the components based on the sections of the parent component.
So the each child component are the each section of the same parent component. But my question how to access the child component objects from parent component? Because most of the examples i see are based on the click event from parent component to view the child component (like dialog) and the value is passed back to the parent html click event and captures the values using emitter and output parameter.
Whereas in my case there is no such click action to trigger the child component. So how to communicate the values from child component to parent component?
In parent component
onDocumentSelect( documentData: IDocument) {
console.log(documentData);
}
<app-document [showDocument] = 'displayDocument' (selectDocument)=onDocumentSelect($event)></app-document>
In Child component:
#Output() selectDocument: EventEmitter<e.IDocument>;
#Input() showDocument: boolean;
I am triggering emit in the function where the data for the DocumentSource is computed.
this.selectDocument.emit(this.DocumentSource.data);
here this.DocumentSource is the dataTable which has value in Child component, that needs to be accessed in parent component.
Apart from this I have similar data for another field of different type needs to be passed to parent component from child component.
I get the below error while page loads
TypeError: Cannot read property 'subscribe' of undefined
In the above code snippet, by changing the type to any solved the issue.
On child component:
#Output() public selectDocument: EventEmitter<any> = new EventEmitter<any>();
On parent component:
onDocumentSelect( documentData: any) {
console.log(documentData);
}
I am using Redux with React Native and I'm having problem in accessing a specific index of the redux store array with the key.
Here's a rough idea of what I'm trying to do. I have a ParentComponent that accesses the reduxStore for a state data and data contains an array of id,title in it.
class ParentComponent extends Component {
dataArray() {
return Object.keys(this.props.data).map(key => this.props.data[key])
}
/*
Consider the dataArray has elements which are an array of `id` & `title`
*/
render() {
return (
<ScrollView style={styles.fragmentContainer}>
{this.dataArray().map((element) => {
return
<ChildComponent
key={element.id}
id={element.id} />
})}
</ScrollView>
)
}
}
Now I wanna access title of each element of the array via the ChildComponent. This is what I'm trying to do to access it:
class ChildComponent extends Component {
render(
return (
<View>
<Text>{this.props.data[this.props.id].title}</Text>
</View>
)
)
}
Obviously the above doesn't work. It's just an idea of what I'm trying to do. I am unable to access the redux store data using a given key. I tried to find out how one can access it but I found no solution. Is my method of accessing the state for the ChildComponent wrong. Can anyone refer me to how I can achieve this?
NOTE: I specifically want to access the state via the ChildComponent. If that's not how it's supposed to work like, please refer me to some other way or some documentation that explains how this is supposed to be done.
If your child component is a class component, you can import connect, set up your reducer in mapStateToProps and bind them in your export.
You can also send the reducer prop value as props from parent to child component. Something like this <Child value={this.props.myData} />. Now in your child component you can refer it as this.props.value. If you use this approach, it doesn't matter if your child is a class component or not. Don't forget to also instance value in your child component creation.
Hope it helps.
First of all I don't see you passing a data prop from your parent to child. Thus you won't get this.props.data in your child component.
I don't understand why would you want to extract title that way when you can pass it as a prop just like you passed id.
If you specifically want to access redux store, then you use connect from react-redux.
Here's a link to see how to do that
http://redux.js.org/docs/basics/UsageWithReact.html
I am working on a chat tool using vue single file components.I am facing a problem,root .vue has child .vue and grandchild .vue, I want to observer children's rendering,to get the root div's height,to change scrollbar position,
i used the $nextTick() http://rc.vuejs.org/api/#vm-nextTick,but it cant observer children's render,so ,is there any way can I try? thanks a lot.
You can use parent child communication of vue to get to know when you child has rendered. Vue provided following event interface:
Listen to an event using $on(eventName)
Trigger an event using
$emit(eventName)
A parent component can listen to the events emitted from a child component using v-on directly in the template where the child component is used.
So you can emit a event in your child component's lifecycle hook like following:
mounted () {
this.$emit('childRendered')
}
In parent component, you can listen to this event or create a method, like following:
this.$on('childRendered', function () {
// change scrollbar position
})
An example of parent child communication: fiddle
This is just for everyone to easily see the workaround that was mentioned by Saurabh in his comment to his answer. I also used the updated lifecycle to wait for the DOM to finish rendering and patching before manipulating it again.
Since updated does not guarantee that all child components have also been re-rendered, use vm.$nextTick inside of updated.
updated: function () {
this.$nextTick(function () {
// Code that will run only after the
// entire view has been re-rendered
})
}