How to update the data of a grandchild component in React - javascript

So I am using 'react-popout' from https://github.com/JakeGinnivan/react-popout to create a popout window has this subWindow component which has its own data fields in it. I have a MainComponent which defines a list of these popoutwindows (there can be mulitple) and as I define this list I also define that the PopoutWindow has a child subWindow (I leave PopoutWindow component package alone). The PopoutWindow is a wrapper.
So I call the subWindow as part of PopoutWindow inside MainComponent and I want to be able to change the data that I pass into subWindow (currentWindowData) and trigger a re-render but right now it is not working AND I want to only change the data of just one of these PopoutWindows in the list, and not any others.
How can I have it so that upon say a button click, I change the data of only ONE of the subWindows but not all of them (assuming multiple PopoutWindows are rendered and in the list)?
<MainComponent>
openWindow() {
const keyId = shortid.generate();
const window= <PopoutWindow
title={keyId}
options={{height: '700px', width: '350px'}}
key={keyId}
>
{
<subWindow key={shortid.generate()}
data={this.state.currentWindowData}
/>}
</PopoutWindow>;
this.setState({
renderSubWindow: true,
subWindowArray: [window, ...this.state.subeWindowArray],
});
}

Related

Deleting a react component from component list deletes the other components in the list

I have a list of components that are added upon button click, so every button click adds one of the components. Each component has a button that can be clicked to delete the component from the list.
Each pair of text "New Item" and button is created as one component in the insertNewCollectorFields function. This function is called when the maroon button is clicked. Each component is added to a list of components "collectorsList" to be displayed. For each component, I use the current length of this collectorsList as the id and key.
This is my code:
import {useEffect, useState} from "react";
export default function Test(){
const [collectorsList, setCollectorsList] = useState([])
const insertNewCollectorFields = () => {
setCollectorsList(collectorsList.concat(
<div id={collectorsList.length} key={collectorsList.length}>
<p>New Item</p>
<button onClick={()=>deleteNewCollectorFields(collectorsList.length)}>Delete New Item</button>
</div>
))
}
const deleteNewCollectorFields = (id) => {
console.log(id)
setCollectorsList(collectorsList.filter((item) => item.id!==id))
}
return <div>
{collectorsList}
<button type={"button"} className={`btn col-auto maroonButton`} onClick={insertNewCollectorFields}>Add Another Collector</button>
</div>
}
I am able to add the components, and I can delete components that were added last without an issue. However, if I delete one of the components that was added first, any component that was added after it is deleted too, and I don't understand why.
This is an example of the issue:
Here I add three components:
Now I delete that third component, and no issue:
If I however delete the first component, all three components disappear, and this is the issue:
I created the list of components as a state. This is my first big project using React. What I know is that on creating a state, the value is updated and should be seen by all the components with the updated value? But apparently on debugging, I found that the "collectorsList" seen by every component in the deleteNewCollectorFields function is limited to the list that was present before creating that component. For example, if collectorsList contained 6 components, component number 3 only sees that there is component 1 and 2 in the collectorsList, and does not see that the collectorsList actually contains 6 components. So on deleting component number 3, the filter process in the delete function results in only component 1 and 2, and everything else disappears from the screen.
I don't understand why this happens and why the components are not able to see the updated list with all the components that were added to it. I also searched for other examples were such a delete function was created and it seems that my method should work, and I couldn't find any case were this problem was faced.
What am I doing wrong? Is there something I understood incorrectly about the use of states?
Your problem is that you are using id={collectorsList.length}, which is wrong, because the .length is changing every time you delete an item and this give wrong id to the deleteNewCollectorFields, just make unique id

Vue propsData not updating dynamically

I've been struggling with this issue for hours:
I've instantiated dynamically a child vue component inside a parent component, and passed in propsData some of the parent's data. The dynamically created child's properties doesn't seem to update when the parent updates.
Please check the example I created for a better understanding (forked from chinchang's example)
As you can see, I'm instantiating Button components both dynamically and statically. The color of the button depends on the type property. I pass the parent's data(the type attribute) as props both to the dynamically and statically created instances. When you insert a new button, by clicking the 'Click to insert' button, a new Button is created, using the parent's current type. After the click event, I switch the parent's type attribute. As you can see the statically created button instance (on the top on the page) changes color, but the dynamically instantiated ones remain the same.
Could you point out my mistake please and help to find a solution?
Thanks,
Ábel
From the docs:
Pass props to an instance during its creation. This is primarily
intended to make unit testing easier.
Setting propsData does not create a parent-child relationship. It simply provides (non-reactive) data to the component. In short, you've chosen a not-very-Vue approach. You shouldn't be concerned with creating components, you should have data items in your viewmodel that Vue then creates components for.
export default {
name: 'app',
components: { Button },
data(){
return {
type: 'secondary',
buttons: []
};
},
methods: {
onClick() {
this.buttons.push(true);
if(this.type === 'primary'){
this.type = 'secondary';
} else {
this.type = 'primary';
}
}
}
}
and
<div ref="container">
<button #click="onClick">Click to insert</button>
<Button v-for="b in buttons" :type="type">Click me!</Button>
</div>
Fixed demo

Accessing a component's state when render() is called

I'm using a component library and I cannot figure this out. I'm new to react and javascript and need help.
There is a component in the library that renders a header panel with tabs.
Component
|_Component.Tab
The Tab component has 2 states that change its appearance when it is clicked. But the click handler and state changes have to be defined by me outside of Tab component. How do I do this?
Seems to me by your question that you need to use props to pass the function to change state from the Component to the Tabs. Something like this:
Component
changeState(value) {
this.setState({ appearance: value });
}
render() {
return (
<div>
<Tab
appearance={this.state.appearance}
onChangeState={this.changeState}
/>
</div>
);
}
Tab
render() {
console.log('Appearance: ', this.props.appearance); // Use it for whatever you need it
return (
<div>
<Button
onClick={(value) => this.props.onChangeState(value)} />
</div>
);
}
Not sure why do you want to handle a function and it’s state outside of the component when it has to be within the Tab component. But here is the solution what you actually have to do in your Tab component to handle your state
Bind your handler function inside a constructor like below
Eg:
this.handlerFunction = this.handlerFunction.bind(this)
Call this.handlerFunction reference in your tab onClick
Eg:
onClick={this.handlerFunction}
Set state in handlerFunction
Eg:
handlerFunction(event){
this.setState({
tabClicked: event.target.value
})
}
Else I guess The outside component should be a child component that you are talking about. If so pass your tab click state as props to your outside component (i.e., child component) and receive that state as props in your child component and do setState there.
If you are still unclear then
Post your component code here. With Just theory it’s little difficult to understand the actual problem that you are talking about.

React/redux + bootstrap, make modal show unique for component

I have a component that shows a modal to pop up some content in my map. I have a pretty straight forward set up :
The JSX looks like this :
<Modal show={this.props.results.showPreviewModal} >
{myPreviewContent}
</Modal>
2 action-creators to open, close, and set the current item :
export function previewAsset(result) {
return {
currentResult: result,
type: actions.PREVIEW_ASSET
};
}
export function closePreviewModal() {
return {
type: actions.CLOSE_PREVIEW_MODAL
};
}
And their reducers :
case actions.PREVIEW_ASSET:
return state.set('currentPreview', action.currentResult).set('showPreviewModal', true);
case actions.CLOSE_PREVIEW_MODAL:
return state.set('showPreviewModal', false);
Now, this seems to work fine. However, the issue is that the component that has the modal inside of it is inside a map, as it is a singular search result (each result component has a some functionality so it is it's own component that is mapped over with results). The issue is that if I have 10 results, this modal opens 10 times when I click the button that fires the previewAsset action.
This makes sense, because the showPreviewModal is accessible by all components, but what I am wondering is if there is a way to make then unique for each component individually, so only the 1 modal opens, not all 10. Unsure how to approach this within react/redux, would very much appreciate any advice, thanks!
An approach I've used successfully is to pull the Modal component out of the loop (or map() in this case), and have a reducer for currentItem or something similar, which gets set when an item is selected (you could also use currentItemIndex, and then select the current item based on that in your connect() call).
In the parent component, you'd have the Modal as a child, and only display it if that currentItem is not null.
Here's a quick JSBin example to show you what I mean:
http://jsbin.com/fefoxoy/edit?html,js,console,output

Replacing child react component with another based on user intreaction or button click

I have created bootstrap modal component in react.
var carModal=<Modal handleHideModal={this.handleHideCarModal}
onConfirm={this.confirmCarModal}
title="Car"
id="CarModal">
<CarStructure callbackParent={this.showCarOptionsUpdate}/>
</Modal>
In car structure I have a form where based on button click I want to remove <CarStructure> child component from the modal carModal and update it with another component with different form structure. How can I replace <CarStructure> with another component having totally different user interface and options?
Remember that the job of a React component's render function is to describe how the component should look at any given point at time, so you don't "remove" or "change" pieces of the DOM so much as you describe when they should change themselves. So, you'll want to base the internal component of <Modal> on some sort of state (which may change throughout the life of the parent component). Something like this might do the trick:
var carModalBody;
if (this.state.something) {
var carModalBody = <CarStructure callbackParent={this.showCarOptionsUpdate} />;
} else {
var carModalBody = <SomeOtherComponent />;
}
var carModal = <Modal handleHideModal={this.handleHideCarModal}
onConfirm={this.confirmCarModal}
title="Car"
id="CarModal">
{carModalBody}
</Modal>

Categories

Resources