react js onclick function doesn't call - reactjs

I am newbie in react js,I want to do onclick in it, but when i click on button it says this is undefined, can anyone please help me how can i resolve this error, I have placed alert to check if this deleteTask is working or not, but that function doesn't call, here is my full code for that
class PalladiumHub extends React.Component {
render() {
return (<tr>
<td>{this.props.name.id}</td>
<td>{this.props.name.name}</td>
<td><button type="button">Edit</button><button onClick={function(e) { this.props.deleteTask(this.props.key) } }>Delete</button></td>
</tr>
)
}
} //{} {}
class CallCRUD extends React.Component {
constructor(props) {
super(props);
this.deleteTask = this.deleteTask.bind(this);
this.state = {
error: null,
isLoaded: false,
items: []
};
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
deleteTask(index) {
alert('sdsd');
console.log(index);
//return false;
let tasks = this.state.items;
tasks.splice(index,1);
this.setState({
items:tasks
})
}
render() {
console.log(this.state.items);
return (<table border="1"> <tr><th>ID</th><th>Name</th><th>Action</th></tr> {
this.state.items.map( (data,index) => {
return <PalladiumHub name={data} key={data.id} deleteTask ={this.deleteTask} />
})
}
</table>
);
}
}
ReactDOM.render(
<CallCRUD />, document.getElementById('root')
);

Do not use functions, they removes this bindings
onClick={function(e) { this.props.deleteTask(this.props.key) } }
change it to
onClick={(e) => this.props.deleteTask(this.props.key)}
also, I would like you to read this

Hello you need to bind your onClick handler.
checkout this page https://reactjs.org/docs/handling-events.html
class PalladiumHub extends React.Component {
onClick = () => {
this.props.deleteTask(this.props.key)
}
render() {
return (<tr>
<td>{this.props.name.id}</td>
<td>{this.props.name.name}</td>
<td><button type="button">Edit</button><button onClick={this.onClick.bind(this)}>Delete</button></td>
</tr>)
}
}

Related

react child component not updating after sibling updates

I'm trying to update a sibling from another sibling but for some reasons it does not update in all cases.
I would appreciate if you can help me to find the issue.
So what I'm trying to do is to update InfoBox component from ProductSync component
I would like my output to look like this:
Case1(sync one product):
history:
Sync started ...
Message from Server
Case2 (sync multi products):
history:
Sync started ...
Message from Server
Sync started ...
Message from Server
Sync started ...
Message from Server
.
.
.
What I actually get is this:
Case1(sync one product):
history:
Message from Server
Case2 (sync multi products):
history:
(Dont get any more message here)
export class Admin extends React.Component {
constructor() {
super();
this.syncProduct = this.syncProduct.bind(this);
this.syncMultiProducts = this.syncMultiProducts.bind(this);
this.updateInfoBox = this.updateInfoBox.bind(this);
this.state = {
infoBox: ["history:"]
};
}
updateInfoBox(newText) {
const newStateArray = this.state.infoBox.slice();
newStateArray.push(newText);
this.setState({
infoBox: newStateArray
});
}
syncProduct(item) {
$.ajax({
datatype: "text",
type: "POST",
url: `/Admin/Sync`,
data: { code: item.Code },
async: false,
success: (response) => {
this.updateInfoBox (response.InfoBox);
},
error: (response) => {
this.updateInfoBox (response.InfoBox);
}
});
}
syncMultiProducts(items) {
/*this does not re-render InfoBox component*/
items.map((item, index) => {
this.syncProduct(item);
});
}
render() {
return (
<div>
<InfoBox infoBox={this.state.infoBox}/>
<ProductSync syncProduct={this.syncProduct} syncMultiProducts={this.syncMultiProducts} updateInfoBox={this.updateInfoBox}/>
</div>
);
}
}
ReactDOM.render(
<Admin />,
document.getElementById("admin")
);
First child(ProductSync.jsx):
export class ProductSync extends React.Component {
constructor() {
super();
this.syncProduct= this.syncProduct.bind(this);
}
syncProduct(item) {
this.props.updateInfoBox("Sync started...");/*this does not re-render InfoBox component*/
this.props.syncProduct(getItemFromDB());
}
syncMultiProducts() {
this.props.updateInfoBox("Sync started...");/*this does not re-render InfoBox component*/
this.props.syncMultiProducts(getItemsFromDB());
}
render() {
return (
<div>
<button onClick={() => this.syncMultiProducts()}>Sync all</button>
<button onClick={() => this.syncProduct()}>Sync one</button>
</div>
);
}
}
Second Child(InfoBox.jsx)
export class InfoBox extends React.Component {
constructor(props) {
super(props);
this.state = {
infoBox: props.infoBox
};
}
componentWillReceiveProps(nextProps) {
this.setState({ infoBox: nextProps.infoBox});
}
render() {
const texts =
(<div>
{this.state.infoBox.map((text, index) => (
<p key={index}>{text}</p>
))}
</div>);
return (
<div>
{Texts}
</div>
);
}
}
Thanks in advance

Using ReactJs to fetch data from an api but getting a blank page with no error

Hello Guys kindly someone assist me with the issue i am having with my code. I am a newbie trying to learn react. i am trying to fetch data from an api. From the browser console i can see the data but when i try to return the data in the Dom i get a blank page. see my code below.
import React, { Component } from "react";
class FetchApi extends Component {
constructor(props) {
super(props);
this.state = {
person: []
};
}
componentDidMount() {
fetch("https://api.randomuser.me/")
.then(res => res.json())
.then(data => console.log(data))
.then(data => {
this.setState({
person: data
});
});
}
render() {
return (
<div>
{this.state.person &&
this.state.person.map(item => (
<li key={item.results.id}>
{item.results.gender} {item.results.location}
</li>
))}
</div>
);
}
}
export default FetchApi;
I have modified your code to the following. In some cases the way you are referencing the properties was wrong. Have made some changes in your componentDidMount and in the render method.
Sandbox for your reference: https://codesandbox.io/s/react-basic-example-nubu7
Hope this resolves
import React, { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
person: []
};
}
componentDidMount() {
try {
fetch("https://api.randomuser.me/")
.then(res => res.json())
.then(data => {
this.setState({
person: data.results
});
});
} catch (e) {
console.log(e);
}
}
render() {
return (
<div>
{this.state.person &&
this.state.person.map(item => (
<li key={item.id.value}>
{item.gender} {item.location.city}
</li>
))}
</div>
);
}
}
export default App;
Check this codesandbox, the response from the fetch API is in this format
{
"results":[
{
"gender":"male",
"name":{
"title":"Monsieur",
"first":"Alois",
"last":"Fernandez"
},
"location":{
"street":{
"number":1856,
"name":"Rue Duquesne"
},
"city":"Untereggen",
"state":"Genève",
"country":"Switzerland",
"postcode":9650,
"coordinates":{
"latitude":"-50.1413",
"longitude":"-23.6337"
},
"timezone":{
"offset":"+5:30",
"description":"Bombay, Calcutta, Madras, New Delhi"
}
},
"email":"alois.fernandez#example.com",
"login":{
"uuid":"04b2ee45-cf07-4015-a5d8-2311f6dc28a1",
"username":"ticklishleopard228",
"password":"forward",
"salt":"V8bDcgux",
"md5":"d521c6488fc4644ccb7e670e9e67bc20",
"sha1":"9673afe219f27817c573a9cb727c209357d386ef",
"sha256":"c13a5bc77dc720a6cc46bc640680e9501225fc94c9bc6ba7fe203fe989a992a0"
},
"dob":{
"date":"1957-11-24T13:46:29.422Z",
"age":63
},
"registered":{
"date":"2003-05-18T19:56:11.397Z",
"age":17
},
"phone":"077 871 56 07",
"cell":"077 461 83 98",
"id":{
"name":"AVS",
"value":"756.1050.9271.56"
},
"picture":{
"large":"https://randomuser.me/api/portraits/men/8.jpg",
"medium":"https://randomuser.me/api/portraits/med/men/8.jpg",
"thumbnail":"https://randomuser.me/api/portraits/thumb/men/8.jpg"
},
"nat":"CH"
}
],
"info":{
"seed":"76a6b875b2ba81dd",
"results":1,
"page":1,
"version":"1.3"
}
}
So you have to set the person in the state to data.results instead of data and access the item in the results accordingly.

How to setState in ComponentDidMount

I have something strange with a react app,
I used it in a django project and want to re-use it in a laravel project but it doesn't want to work properly ...
Here is the code of my component :
import React from "react"
import {LeftControl, RightControl, CountControl } from './controls'
import {Slide} from './slide'
import axios from "axios"
export default class Slider extends React.Component {
constructor(props){
super(props);
this.state = {
items : [],
active:0
}
}
componentDidMount() {
axios.get('/coming')
.then((res)=>{
this.setState({ items: res.data, active: 0})
});
setInterval( () => {
this.goToNextSlide()
},5000);
}
goToPrevSlide = () => {
const n = this.state.items.length
if (this.state.active == 0) {
this.setState({active : n-1})
} else {
this.setState({active: this.state.active - 1})
}
}
goToNextSlide = () => {
const n = this.state.items.length
if (this.state.active == n-1){
this.setState({active : 0})
} else {
this.setState({active: this.state.active +1})
}
}
render(){
return(
<div className="slider">
<div className="slider__controls">
<CountControl active={this.state.active} length={this.state.items.length} />
<LeftControl goToPrevSlide={this.goToPrevSlide} />
<RightControl goToNextSlide={this.goToNextSlide}/>
</div>
<div className="slider__items">
{
this.state.items
.map((item, i) => (
<Slide active={this.state.active} index={i} key={i} id={item.id} first_name={item.first_name} last_name={item.last_name} role={item.role} conference_date={item.conference_date} thumbnail={item.thumbnail} />
))
}
</div>
</div>
)
}
}
Uncommenting the setState in componentDidMount raise the following error :
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
in Slider
The component works well on my other project ...
Anyone would have an idea what is the problem ?
Thank you
As riwu commented, you get the warning because the axios call and timer you define in componentDidMount try to set the state of Slider after it has been unmounted. Do the following instead:
export default class Slider extends React.Component {
...
constructor(props) {
super(props);
this._isMounted = false;
this.state = {
items : [],
active:0,
}
}
componentDidMount() {
this._isMounted = true;
axios.get('/coming')
.then((res) => {
if (this._isMounted) {
this.setState({ items: res.data, active: 0})
}
});
this.timer = setInterval(() => {
this.goToNextSlide();
}, 5000);
}
componentWillUnmount() {
this._isMounted = false;
clearInterval(this.timer);
}
...
}

React: Issues with Conditional Rendering

In my React-App, i use the Firebase SDK. If a user wants to reset his password, he will be redirected to a page within my app. If the code is valid, the component <PWResetConfirmForm /> should be rended. If the code is invalid, the component <PWResetOutdatedForm /> is to be rendered.
My Page Component looks like this:
class PWResetConfirmPage extends Component {
constructor(props) {
super(props);
this.state = {};
this.verfiyResetPassword = this.verfiyResetPassword.bind(this);
}
verfiyResetPassword() {
const params = (new URL(`http://dummy.com${this.props.location.search}`)).searchParams;
const code = params.get("oobCode")
auth.doVerfiyPasswordReset(code)
.then(function () {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetConfirmForm></PWResetConfirmForm>
</div>
);
})
.catch(function () {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetOutdatedForm></PWResetOutdatedForm>
</div>
);
})
}
render() {
return (
<div>
{this.verfiyResetPassword()}
</div>
);
}
}
export default PWResetConfirmPage
When i try to run, i get a blank page and not error.
Where is my issue and how can i fix that?
Thank you very much for your help and for your time
You will not be able to return JSX from within then()/catch() of auth.doVerfiyPasswordReset() like that. You can instead approach this by taking advantage of React.Component lifecycle method componentDidMount and using setState() to manipulate state properties for conditional rendering. I've added state properties to the component, one to track whether loading (API call has completed) and one to track whether the call was a success (then) or failure (catch). These properties are used to conditionally generate JSX content for rendering. This is assuming that verfiyResetPassword() is intended to run when the component is first mounted, instead of every time render() is called:
class App extends Component {
constructor() {
super();
this.state = {
isResetVerified: null,
loading: true
};
}
componentDidMount() {
this.verfiyResetPassword();
}
verfiyResetPassword() {
const params = (new URL(`http://dummy.com${this.props.location.search}`)).searchParams;
const code = params.get("oobCode")
auth.doVerfiyPasswordReset('foobar')
.then(() => {
this.setState({
...this.state,
isResetVerified: true,
loading: false
});
})
.catch(() => {
this.setState({
...this.state,
isResetVerified: false,
loading: false
});
})
}
getContent() {
if (this.state.loading) {
return (
<div>Loading...</div>
);
} else {
if (this.state.isResetVerified) {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetConfirmForm></PWResetConfirmForm>
</div>
);
} else {
return (
<div className="HomePage-Main">
<TopBar></TopBar>
<PWResetOutdatedForm></PWResetOutdatedForm>
</div>
);
}
}
}
Here is a basic example in action.
Also, in the constructor this.verfiyResetPassword = this.verfiyResetPassword.bind(this); would only be needed if verfiyResetPassword() is executed by a DOM event such as button onClick or similar.
Hopefully that helps!
I could still fix the error myself:
class PWResetConfirmPage extends Component {
constructor(props) {
super(props);
this.state = {
isValid: false,
code: "",
};
this.verfiyResetPassword = this.verfiyResetPassword.bind(this);
}
componentDidMount() {
const params = (new URL(`http://dummy.com${this.props.location.search}`)).searchParams;
const code = params.get("oobCode")
this.setState({code:code})
auth.doVerfiyPasswordReset(code)
.then(() => {
this.setState({
...this.state,
isValid: true,
});
})
.catch(() => {
this.setState({
...this.state,
isValid: false,
});
})
}
verfiyResetPassword() {
if (this.state.isValid) {
return (
<div>
<TopBar></TopBar>
<PWResetConfirmForm code={this.state.code}></PWResetConfirmForm>
</div>
);
} else {
return (
<div>
<TopBar></TopBar>
<PWResetOutdatedForm></PWResetOutdatedForm>
</div>
);
}
}
render() {
return (
<div className="HomePage-Main">
{this.verfiyResetPassword()}
</div>
);
}
}
export default PWResetConfirmPage

React force componentDidMount

I have the following:
import React from 'react';
import axios from 'axios';
class FirstName extends React.Component {
constructor(props) {
super(props);
this.state = {
submitted: false
};
}
getName () {
var name = this.refs.firstName.value;
this.setState(function() {
this.props.action(name);
});
}
handleSubmit (e) {
e.preventDefault();
this.setState({ submitted: true }, function() {
this.props.actionID(2);
this.props.activeNav('color');
});
}
render () {
return (
<div>
<h2>tell us your first name</h2>
<form>
<input
type="text"
ref="firstName"
onChange={this.getName.bind(this)}
/>
<div className="buttons-wrapper">
<button href="#">back</button>
<button onClick={this.handleSubmit.bind(this)}>continue</button>
</div>
</form>
</div>
);
}
};
class PickColor extends React.Component {
backToPrevious (e) {
e.preventDefault();
this.props.actionID(1);
this.props.activeNav('name');
}
goToNext (e) {
e.preventDefault();
this.props.actionID(3);
this.props.activeNav('design');
this.props.displayIconsHolder(true);
}
getColorValue(event) {
this.props.color(event.target.getAttribute("data-color"));
}
render () {
var colors = ['red', 'purple', 'yellow', 'green', 'blue'],
colorsLink = [];
colors.forEach(el => {
colorsLink.push(<li
data-color={el}
key={el}
onClick={this.getColorValue.bind(this)}
ref={el}>
{el}
</li>
);
});
return (
<section>
<ul>
{colorsLink}
</ul>
<button onClick={this.backToPrevious.bind(this)}>back</button>
<button onClick={this.goToNext.bind(this)}>continue</button>
</section>
);
}
}
class ConfirmSingleIcon extends React.Component {
goBack () {
this.props.goBack();
}
confirmCaptionandIcon (event) {
var optionID = event.target.getAttribute("data-option-id"),
name = event.target.getAttribute("data-option-name");
this.props.setOptionID(optionID);
this.props.setIcon(1, name, optionID, false);
}
goNext () {
this.props.goNext();
}
render () {
console.log(this.props.currentState);
var options = [],
that = this;
this.props.iconOptionsList.forEach(function(el){
options.push(<li onClick={that.confirmCaptionandIcon.bind(that)} key={el.option} data-option-name={el.option} data-option-id={el.id}>{el.option}</li>);
});
return (
<div>
<h2>Choose your caption</h2>
<h3>
{this.props.selectedIcon}
</h3>
<ul>
{options}
</ul>
<button onClick={this.goBack.bind(this)} >back</button>
<button onClick={this.goNext.bind(this)} >confirm</button>
</div>
);
}
}
class ConfirmCaption extends React.Component {
handleClick () {
var currentState = this.props.currentState;
this.props.setIcon(currentState.icon_ID, currentState.selectedIcon, currentState.option_ID, true);
this.props.setIconVisiblity(true);
this.props.setIconListVisiblity(false);
}
render () {
console.log(this.props.currentState);
return (
<div>
<p onClick={this.handleClick.bind(this)}>confirm icon and caption</p>
</div>
);
}
}
class ChooseIcon extends React.Component {
constructor(props) {
super(props);
this.state = {
icons: [],
iconList: true,
confirmIcon: false,
confirmCaption: false,
selectedIconOptions: '',
icon_ID: '',
option_ID: '',
selectedIcon: ''
};
this.setOptionID = this.setOptionID.bind(this);
this.setIconVisiblity = this.setIconVisiblity.bind(this);
this.setIconListVisiblity = this.setIconListVisiblity.bind(this);
}
setOptionID (id) {
this.setState({ option_ID: id })
}
setIconVisiblity (onOff) {
this.setState({ confirmIcon: onOff })
}
setIconListVisiblity (onOff) {
this.setState({ iconList: onOff })
}
componentDidMount() {
var url = `http://local.tshirt.net/get-options`;
axios.get(url)
.then(res => {
this.setState({ icons:res.data.icons });
});
}
handleClick (event) {
var iconId = event.target.getAttribute("data-icon-id"),
that = this;
this.state.icons.forEach(function(el){
if(el.id == iconId){
that.setState(
{
confirmIcon: true,
iconList: false,
selectedIcon: el.name,
icon_ID: iconId,
selectedIconOptions: el.option
}
);
}
});
}
goBack () {
this.setState(
{
confirmIcon: false,
iconList: true
}
);
}
goNext () {
this.setState(
{
confirmIcon: false,
iconList: false,
confirmCaption: true
}
);
}
render () {
var icons = [];
this.state.icons.forEach(el => {
icons.push(<li data-icon-id={el.id} onClick={this.handleClick.bind(this)} key={el.name}>{el.name}</li>);
});
return (
<div>
{this.state.iconList ? <IconList icons={icons} /> : ''}
{this.state.confirmIcon ? <ConfirmSingleIcon goBack={this.goBack.bind(this)}
goNext={this.goNext.bind(this)}
setIcon={this.props.setIcon}
selectedIcon={this.state.selectedIcon}
iconOptionsList ={this.state.selectedIconOptions}
setOptionID={this.setOptionID}
currentState={this.state} /> : ''}
{this.state.confirmCaption ? <ConfirmCaption currentState={this.state}
setIcon={this.props.setIcon}
setIconVisiblity={this.setIconVisiblity}
setIconListVisiblity={this.setIconListVisiblity} /> : ''}
</div>
);
}
}
class IconList extends React.Component {
render () {
return (
<div>
<h2>Pick your icon</h2>
<ul>
{this.props.icons}
</ul>
</div>
);
}
}
class Forms extends React.Component {
render () {
var form;
switch(this.props.formID) {
case 1:
form = <FirstName action={this.props.action} actionID={this.props.switchComponent} activeNav={this.props.activeNav} />
break;
case 2:
form = <PickColor displayIconsHolder={this.props.seticonsHolder} color={this.props.colorVal} actionID={this.props.switchComponent} activeNav={this.props.activeNav} />
break;
case 3:
form = <ChooseIcon setIcon={this.props.setOptionA} />
break;
}
return (
<section>
{form}
</section>
);
}
}
export default Forms;
"ChooseIcon" is a component that will get used 3 times therefore everytime I get to it I need to bring its state back as if it was the first time.
Ideally I would need to make this ajax call everytime:
componentDidMount() {
var url = `http://local.tshirt.net/get-options`;
axios.get(url)
.then(res => {
this.setState({ icons:res.data.icons });
});
}
is there a way to manually call componentDidMount perhaps from a parent component?
React handles component lifecycle through key attribute. For example:
<ChooseIcon key={this.props.formID} setIcon={this.props.setOptionA} />
So every time your key (it can be anything you like, but unique) is changed component will unmount and mount again, with this you can easily control componentDidMount callback.
If you are using the ChooseIcon component 3 times inside the same parent component, I would suggest you to do the ajax in componentDidMount of the parent component like this (exaclty how you have in your example, in terms of code)
componentDidMount() {
var url = `http://local.tshirt.net/get-options`;
axios.get(url)
.then(res => {
this.setState({ icons:res.data.icons });
});
}
and then pass this data down to the ChooseIcon component
render() {
return (
//do your stuff
<ChooseIcon icons={this.state.icons}/>
)
}
after this you will only need to set the received props in your ChooseIconcomponent, for that you only need to change one line in it's constructor:
constructor(props) {
super(props);
this.state = {
icons: props.icons, // Changed here!
iconList: true,
confirmIcon: false,
confirmCaption: false,
selectedIconOptions: '',
icon_ID: '',
option_ID: '',
selectedIcon: ''
};
this.setOptionID = this.setOptionID.bind(this);
this.setIconVisiblity = this.setIconVisiblity.bind(this);
this.setIconListVisiblity = this.setIconListVisiblity.bind(this);
}
The parent component can use a ref to call the function directly.
However, trying to force this function feels like a smell. Perhaps lifting the state higher up the component tree would solve this problem. This way, the parent component will tell ChooseIcon what to show, and there will not be a need to call componentDidMount again. Also, I assume the Ajax call can also occur once.

Resources