"this" becomes undefined after certain button click (ReactJS) - javascript

So, I am trying to save the selected option once the radio button is clicked. It is working fine until I press one of the buttons I have in the following code
{Object.keys(this.state.activeContent).map((key, index) =>
<input type="radio" name="key" value={key}
checked={this.checkOption(this.state.activeContent[key].id)}
onChange={() => this.saveKey_Index(this.state.activeContent[key].id, index)} />
)}
<button onClick={() => this.saveActive(this.state.activeContent)}>Save Active</button>
<button onClick={() => this.runHTML("<html> <title> test </title> </html>")}>Play</button>
The "Play" button gives no error and I can then click from the active list the elements I want. But when I click on "save active" I cannot click on any of the items in my list I get the following error:
https://ibb.co/hpJp48
Here are both of the functions:
Play:
runHTML(htmls) {
console.log(htmls)
this.setState({moved: true})
var template = { htmlContent: this.state.htmlContent };
return (<div dangerouslySetInnerHTML={template} />)
}
Save Active:
saveActive(list) {
this.setState = ({ moved: true })
}
And the error I am getting is from:
saveKey_Index:
saveKey_Index(key, index) {
this.setState({ savedKey: key })
this.setState({ savedIndex: index })
}
And yes I have binded the saveActive and saveKey_Index (the error is from saveKey_Index apparently)
this.saveKey_Index = this.saveKey_Index.bind(this)
this.saveActive = this.saveActive.bind(this)
Why am I getting error after saveActive button and not after play? I can setState in the play button even though it is not binded as well. Why is that?

You're overwriting your component's setState() function with this code:
saveActive(list) {
this.setState = ({ moved: true })
}
There shouldn't be an = there, just
saveActive(list) {
this.setState({ moved: true })
}

Related

dynamic Button class does not update after the array change

So I have an array of objects. I iterate through this array and create a button for each object.
When a button is pressed that object of the button pressed has a value "active" that will be set to true. when another button is pressed its "active" value is now true all all the other ones are turned to false.
it looks like this
myarray.map(item =>
<Button
className={item.active? "btn-active" : "btn-disabled"}
onClick={() => setActive(item);
}}
>
{item.active? "Checking..." : "Start"}
</Button>
)
The behavior I expect is when a button is pressed it turns to action, and all the rest remain inactive, when a new button is pressed the new button is now active and all the rest are disabled. only one active button at a time.
However, the issue I am having is when a new button is pressed it turns to active, but the old one does not change class and stays active also even though it "active" property is set to false.
Any idea how can I fix this behavior?
Without a full picture of how you are using state, here is a working example. Another issue I seen is that you are missing a key on your mapped jsx element.
It's possible you are not mutating myarray statefully.
import "./styles.css";
import React from "react";
export default function App() {
const [myarray, setMyarray] = React.useState([
{ id: 1, active: false },
{ id: 2, active: false }
]);
const setActive = (id) => {
setMyarray((prev) =>
prev.map((item) => {
if (item.id === id) {
return { ...item, active: true };
}
return { ...item, active: false };
})
);
};
return (
<div className="App">
{myarray.map((item) => (
<button
key={`button-${item.id}`}
className={item.active ? "btn-active" : "btn-disabled"}
onClick={() => setActive(item.id)}
>
{item.active ? "Checking..." : "Start"}
</button>
))}
</div>
);
}
https://codesandbox.io/s/flamboyant-shirley-i24v0z

On cancel click not able to set previous data in my react app

I have created dynamic fields from JSON data, and I am successfully rendering on UI
Initially all the fields are disabled.
Once I click on edit I am making particular row editable which is working fine
On click of cancel what I want to do is make the fields disabled again and it should take the previous (initial value)
Issue
When I click on cancel I am setting the initial data aging but it is not taking, I am using react-form-hook for form validation, there we have reset() function but that too is not working.
What I am doing is
Getting data from main component and setting it to some state variable like below
useEffect(() => {
if (li) {
setdisplayData(li);
setCancelData(li);
}
}, [li]);
Now using displayData to render the elements
On click of Edit I am doing this
const Edit = () => {
setdisabled(false);
};
and on click of cancel I am doing below
const cancel = () => {
setdisabled(true); //disbaled true
console.log(cancelData);
setdisplayData(cancelData); setting my main data back to previous one
reset(); // tried this reset of react hook form but it did not work
};
I am using defaultValue so that when I click on Edit the field should allow me to edit.
Here is my full working code
To fix this issue I changed up your code to use value instead of defaultValue. Additionally added an onChange event handler which updates the displayData state whenever <input> changes value. Moreover, you do not need the cancelData state at all since the li prop has the original values.
Now when the onClick for the cancel button is fired, it resets the value of displayData state to whatever li originally was. Here is the modified code:
import React, { useState, useEffect } from "react";
import { useForm } from "react-hook-form";
function component({ li, index }) {
const [disabled, setdisabled] = useState(true);
const [displayData, setdisplayData] = useState(null);
const { register, reset, errors, handleSubmit, getValues } = useForm();
useEffect(() => {
if (li) {
setdisplayData(li);
}
}, [li]);
const Edit = () => {
setdisabled(false);
};
const cancel = () => {
setdisabled(true);
console.log(li);
// Reset displayData value to li
setdisplayData(li);
reset();
};
return (
<div>
<div>
{disabled ? (
<button className="btn btn-primary" onClick={Edit}>
Edit
</button>
) : (
<button className="btn btn-warning" onClick={cancel}>
Cancel
</button>
)}
</div>
<br></br>
{displayData !== null && (
<>
<div className="form-group">
<label htmlFor="fname">first name</label>
<input
type="text"
name="fname"
disabled={disabled}
value={displayData.name}
// Update displayData.name everytime value changes
onChange={({ target: { value } }) =>
setdisplayData((prev) => ({ ...prev, name: value }))
}
/>
</div>
<div className="form-group">
<label htmlFor="lname">last name</label>
<input
type="text"
name="lname"
disabled={disabled}
value={displayData.lname}
// Update displayData.lname everytime value changes
onChange={({ target: { value } }) =>
setdisplayData((prev) => ({ ...prev, lname: value }))
}
/>
</div>
</>
)}
<hr></hr>
</div>
);
}
export default component;
Hope this helps. Drop a comment if it's still not clear :)

Toggle view dynamically on click ReactJs

I have mapped list of data from JSON. When I clicked on of the item it should open a crawl with additional details from the same JSON file. I am able to map everything one I clicked bit I was not able to toggle. How do I do toggling.
This is my render method
render() {
return (
<div>
<h1>API</h1>
<div>
{this.state.apis.map(api => (
<div
key={api.id}
id={api.id}
onClick={this.handleCrawl}>
{api.title}
</div>
))}
</div>
<div>
{this.state.apis.map(api => (
<div
key={api.id}
id={api.id}>
{this.state.showCrawl[api.id] && (
<SwaggerUI url={api.opening_crawl}/>
)}
</div>
))}
</div>
</div>
);
}
This is the method for toggling. When I clicked an item the SwaggerUI component shows up and If I clicked the same link it hides.
The problem is if I clicked the 2nd link 1st link still shows. I need other view to be closed.
handleCrawl = e => {
const { id } = e.target;
this.setState(current => ({
showCrawl: { ...current.showCrawl, [id]: !current.showCrawl[id] }
}));
};
just don't spread the previous state's props.
try this:
handleCrawl = e => {
const { id } = e.target;
this.setState(current => ({
showCrawl: { [id]: !current.showCrawl[id] }
}));
};
Because in your code:
initial state:
{showCrawl: {}}
Say first time you click the first one(id: 1), your state become:
{showCrawl: {1: true}}
then u click the second one(id: 2)
{showCrawl: {1: true, 2: true}}
That's not your expected. Right?
So just don't spread the property, it should be going well.
In general, you can show or hide an element in a react component like this:
{this.state.showComponent ? (<Component/>) : (null)}
as an alternative, you can control the hiding/showing of the element in the component itself, with a show prop:
<Component show={this.state.showComponent} />
-- edit
I think I misunderstood your problem. Your problem is that you only want SwaggerUI to show for one thing at a time, but it's showing for multiple.
This is because of the way you designed your function,
handleCrawl = e => {
const { id } = e.target;
this.setState(current => ({
showCrawl: { ...current.showCrawl, [id]: !current.showCrawl[id] }
}));
};
You're only ever ADDING ids to showCrawl, not changing the ids that you toggled previously. You'll have to fix that function

Passing value from Parent to Child in Reactjs using props

I am trying to pass theExpert.email value to another child component whenever i click on send questions button.
This is the constructor of the Parent class
constructor() {
super();
this.state = {
textbox: '',
category: '',
exp: '',
hide: false
};
this.hideButton = this.hideButton.bind(this);
}
The follow function hides the button once it is clicked and saves the value of the theExpert.email in exp, (value is passed correctly since console.log prints it)
hideButton (value) {
this.setState({ hide: true });
this.setState({
exp: value
});
console.log(value)
}
And here is the button that once I click on it it passes the value to hideButton
<div>
{!this.state.hide ? (
<button onClick={() => this.hideButton(theExpert.email)}>Ask Me!</button>
) : null}
</div>
Now what i want to do is once i click on Send Questions button i get redirected to the child component Questions.js and pass the value of theExpert.email to that component
The button Send Questions:
<div>
<p>
{(this.state.hide) && (
<Link to="/questions">
<button
style={{ background: "green", color: "white" }}
>
Send Question
</button>
</Link>
)}
</p>
</div>
How can i retrieve value in the child class to create a post request using it
I think the issue us due to react being lazy. Basically you are just setting hide to true and re-rendering your component and all of its children but never setting exp the expected value.
So instead of
hideButton (value) {
this.setState({ hide: true });
this.setState({
exp: value
});
console.log(value)
}
try
hideButton (value) {
this.setState(prevState=>{
prevState= {
...prevState
hide: true ,
exp: value
}
return prevState
});
}

React invoking function calling setState passed in props of a stateless component

I am working on filter component being made with React.JS.
A few of those filtering components are embedded in a panel (div). The wrapping parts of the panel look like the below:
Initiative <a onClick={() => {this.setState({ showInitiatives: true })}} className="milestone-list-link" href="#initiative">
{this.state.selectedInitiative}
<InitiativeSelector
initiatives={initiatives || {}}
show={this.state.showInitiatives}
selector={
() => {
console.log('called selector state:', this.state)
this.setState({ showInitiatives: false })
}
}
/>
<FilterIcon />
</a>
My <InitiativeSelector /> looks like the below:
const InitiativeSelector = ({initiatives, show, selector}) => {
return (show) ? (
<div className="list-filter">
<div>
<input placeholder="Search..." />
</div>
<ul>
{
Object.values(initiatives).map((initiative, i) => <li onClick={() => {selector()}} key={i}>{initiative.name}</li> )
}
</ul>
</div>
) : null
}
When I run this, my selector does get called. Hence, I see state printed to the console. However, this.setState({ showInitiatives: false }) does not seem to do anything. My modal does not hide, and the second (etc) time I click on the <li>, showInitiatives still set to true.
This is because click event bubbles up the DOM tree combined with async nature of setState
First li.onClick fires calling selector which calls setState({ showInitiatives: false})
Then a.onClick fires calling setState({ showInitiatives: true }). You could check it is true say by adding log statement to it.
Now you have 2 pending updates
{ showInitiatives: false}
{ showInitiatives: true}
which when merged is noop.
You need to either stop event propagation inside li.onClick by calling e.stopPropagation() or rethink what a.onClick handler is doing.

Categories