I have 2 components. In one component I render map of table rows =>
this is place, where tDs.map is rendered
this.state.dataOld.map(it =>(
<>
<tr onClick={()=>{it.selected_=!it.selected_;this.forceUpdate()}} value={it} key={it.id}>
{this.tDs.map(fnc => fnc(it,this.hide,this))}
</tr>
</>))
dataOld is array of 2 objects
tDs is array like
function(it,hide,a){return !hide.id ? <td>{it.id}</td> : null},
function(it,hide,a){return !hide.category3 ? <td>{it.category3}</td> : null},
function(it,hide,a){return !hide.edit ? <td>
<Button onClick={() => a.setState({edit:!a.state.edit,element:it})}>
</Button>
</td> : null}
the thing i interested in is a.setState({edit:!a.state.edit,element:it})}
I render another component inside of first
<Edit isOpen={this.state.edit} editBack={this.editBack} th={this} element={this.state.element}/>
I transfer my this.state.element to Edit, inside Edit component I'm doing something like this:
elem = {};
componentDidUpdate(){
this.elem = this.props.element
console.log(this.elem)
}
...
<Input onChange={ e => {this.elem.packagingType = e.target.value; console.log(e.target.value)} } ... />
so, the problem is: I transfer this.state.element to Edit component, then in Edit component I make new variable elem and make it be equal to this.props.elem I transferred
the problem starting here, the first, (original, natural) this.state.element is changing, but I dont change dataOld, I dont change any element that has been rendered, I really dont undestand, how it works here.
My guess was about this place
<Edit isOpen={this.state.edit} editBack={this.editBack} th={this} element={this.state.element}/>
I think that when I'm doing element={this.state.element} I somehow connect this 2 things and when I change element inside of Edit, the natural this.state.element is changing too.
Codesandbox example:
https://codesandbox.io/embed/7wk8689op6?fontsize=14
when you press a button near every row, then change data and press cancel, the original data is changing, I dont understand why
I think I understood the question.
When I put an object to the Edit component, and then change an object inside of component, the original object is changing too because I didn't make a new version of this object, but I gave to Edit a link to this object.
Related
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
I learn React and JavaScript and now I have this problem
Here's a Codesandbox
What happens is like this:
In the Codesandbox at FileEditor.jsx: I mock it like this:
// Mocking the tag list just to test it
const tagMock = ['11111']; // THIS WORKS WITH ONLY ONE ITEM
// Mocking the tag list just to test it
//const tagMock = ["11111", "22222", "33333"]; // THIS DOES NOT WORK WITH MULTIPLE ITEMS
The tagMock that works in the first one with only one array value.
The tagMock that does not work is the one with 3 values.
(when you star sandbox the tagMock with only one array value is use, please change to tagMock with 3 array values to see the error)
If you look further down in FileEditor.jsx you see where tagMock is use like this:
{tagMock.map((tag) => (
<div className="tagInput">
<button
className="btn btn-warning btn-sm"
disabled={false}
key={tag}
type="button"
// onClick={() => remove(skill)}
>
<TagName tag={tag} />
</button>
</div>
))}
Every button created in this map loop have it's own <TagName tag={tag} />
The TagName is a component that is connected to the Redux Store and there
it selected (using reselect), the store tags and then return the tag name only.
The button name text is by so dynamically set like this:
In the image above, the "name2" button text is set" .
The problem is that this does not work if more then 1 button like this:
//const tagMock = ["11111", "22222", "33333"]; // THIS DOES NOT WORK WITH MULTIPLE ITEMS
The error I get is the name is not defend in the tagName.jsx file.
Why does this happen? I understand it's some form of component duplications issue that the map loop can't create the tagName Component as it should, but I can't figure it out.
ok I solved it,
WRONG:
state.global.tags.find(tag => tag.id > ownProps.tag);
RIGHT:
state.global.tags.find(tag => tag.id === ownProps.tag);
It's a basic question but I searched for a guide without success...
I want to have a list of dropdowns and inputs and each dropdown will change the input next to it.
var list = [{ name: "foo1"}, {name: "foo2"}];
return (
{list.map( (name) => {
return (<div>
<dropdown data={someData}
onChange={(ev) => {
if(ev.value == 'clearIt')
<CHANGE THE NEAR INPUT VALUE>
}
}/>
<input value={name.name} />
</div>)
})});
I don't want to use DOM nor ref cause I understood that it's better to avoid it.
Any suggestions?
Or maybe the ref is the only option?
Thanks
So you can achieve this by doing the following steps:
Create a new component and move the dropdown and input to this new component.
Add state to your component by following this example:
https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
Add an event listener onChange to the dropdown with an event handler which can update the state you created in the first step. (Remember to bind the handler in the constructor.
Add the new component within the div element of this example you gave and pass the relevant data you need to the new component you created.
This should allow you to update only the input next to the dropdown. Also it allows you to have different data for each dropdown you created.
I am new with formik and I have a very annoying problem that I am stuck on with days. So basically I have a parent component in which I have a code like this:
const refs=[]
{data.map((v,i) =>
<Child formikRef={refs}}/> )}
And my child component uses formik:
...
<Formik
innerRef={i => props.formikRef.push(i)}
....../>
So my Child component is rendered a couple of times in my parent component, and I need to track the values of each in my parent component. To be more clear, when I click on button that is located in my parent component, I need to have the values from each (I need to pass data from child to parent component). That's why I am using innerRef. The problem is that I am using an array of refs to track values of each rendered , and a new value is added in the array every time I change a field in my form, so I have far more elements in my array than I should have. I think innderRef is triggered each time a change in a field is made, instead of only onSubmit. How I can solve this problem? Pls help.
You could try like below, Here we are passing index value to Child component to have Formik ref in the same place.
const refs=[]
{data.map((v,i) =>
<Child index={i} formikRef={refs}}/>
)}
<Formik
innerRef={props.formikRef[props.index]}
/>
I have a fancy UI in which have a few 'panes' with dividers in between that let you change what each one does. Say I have two different components - a to-do list and a simple text editor. I want you to be able to change the component present in each pane to make a flexible UI. For example, I might want to change the pane on the left from a text editor to a to-do list. Assuming I have a parent element Pane, how could I replace one of its children with another?
<Pane>
<TextEditor /> /* I want to replace that with a <ToDoList /> when I press a button */
<SomeOtherComponentOnTheRight />
</Pane>
I've tried storing React.Children.toArray(this.props.children) in the <Pane />'s state (as this.state.currentChildren), and replacing the element there, but for some reason I can't find a way to get the index of <TextEditor /> in the <Pane />'s this.state.currentChildren because for some reason this.props.children does not preserve children's props, and so I can't transmit data through it.
Sorry if I've overcomplicated this, but I simply want to know how to change a component's children dynamically.
You could check the state in your JSX to change what is displayed such as:
<Pane>
{ this.state.showEditor ? <TextEditor/> : <ToDoList /> }
<SomeOtherComponentOnTheRight />
</Pane>
Elsewhere in your code you would have some button that invokes an onClick event handler that would set the state of 'showEditor' to true/false depending on the previous state.
You can store the selected components in an array or object, then assign the selected component to a variable (just make sure it starts with an uppercase letter) and then use it as a component:
const routes = {
a: TextEditor,
b: ToDoList
};
const ChosenComponent = routes['a']; // select your component and store in variable
return (
<Pane>
<ChosenComponent />
<SomeOtherComponentOnTheRight /> {/* render selected variable as component */}
</Pane>
);