ReactJS : callback error - javascript

I want to send my counter on my parent component but I have an error. I tried different code but none works.
I just want to send the counter and afterwards the score, if I can.
DuelTurn.JS
state = {
compteur: 0
}
constructor(props) {
super(props)
}
componentWillMount() {
this.setState({compteur: this.state.compteur++}, () => {
this.props.callback(this.state.compteur)
})
}
handleClick(step) {
if(step === true) {
console.log('gagné')
} else {
console.log('perdu')
}
}
render() {
return (
<div>
<div className="turn-player">Cest le tour de {this.props.pseudo} !</div>
<div className="text-left">
{this.props.data[0].pseudo}
<div>{this.props.firstScore}</div>
</div>
<div className="text-right">
{this.props.data[1].pseudo}
<div>{this.props.secondScore}</div>
</div>
<div className="clear"></div>
<div className="question"><div>Question :</div>La france a remporté la coupe du monde 98.</div>
<div onclick={this.handleClick(true)} className="true">Vrai</div>
<div onclick={this.handleClick(false)} className="false">Faux</div>
</div>
)
}
}
DuelGame.js
class DuelGame extends React.Component {
state = {
compteur: 0,
firstUser: this.props.dataUser[0].pseudo,
secondUser: this.props.dataUser[1].pseudo,
firstScore: 0,
secondScore: 0,
}
constructor(props) {
super(props)
}
receiveCallBack = (compteur) => {
this.setState({compteur})
console.log(compteur)
}
userTurn() {
if(this.state.compteur == 0 % 2) {
return <DuelTurn key={this.state.firstUser}
pseudo={this.state.firstUser}
firstScore={this.state.firstScore}
secondScore={this.state.secondScore}
compteur={this.state.compteur}
data={this.props.dataUser}
callback={this.receiveCallback}/>
} else {
return <DuelTurn
key={this.state.secondUser}
pseudo={this.state.secondUser}
firstScore={this.state.firstScore}
secondScore={this.state.secondScore}
compteur={this.state.compteur}
data={this.props.dataUser}
callback={this.receiveCallback}/>
}
}
render() {
return (
<div>{this.userTurn()}</div>
)
}
}
And my error is:
bundle.js:36630 Uncaught TypeError: _this2.props.callback is not a function
How to fix it?

Here is your issue, you have defined the function as receiveCallBack while you are calling this as receiveCallback (B,b).
other than that you are getting empty data in your props, I suggest you put an extra check before rendering data. So instead of this.props.dataUser[0] use this.props.dataUser && this.props.dataUser[0] and like wise for your this.props.dataUser[1] use this.props.dataUser && this.props.dataUser[1]
same goes for your this.props.data[0] and this.props.data[1] use conditional rendering there as well.
That should make it work
Here is a working version of your code
https://codesandbox.io/s/3196py0vqq

Related

React : Uncaught TypeError: Cannot read property 'i' of undefined

I have a problem with my code:
class Albs extends React.Component{
constructor(props){
super(props);
this.state = {
i: 0,
anh: this.props.hinhanh[this.state.i]
};
var hinhanh = ["1.png", "2.png", "3.png"];
this.state.i = this.state.i.bind(this);
}
nextPic(){
this.setState({i: this.state.i++});
}
backPic(){
this.setState({i: this.state.i--});
}
render(){
return(
<div>
<img src={this.state.anh}/>
<br/>
<button onClick={nextPic}>Next</button>
<button onClick={backPic}>Back</button>
</div>
)
}
}
ReactDOM.render(
<Albs/>,
document.getElementById('root')
);
In console it shows: Uncaught TypeError: Cannot read property 'i' of undefined. Reason please?
You need to bind the class this to your methods nextPic and backPic as you do with this.state.i (I don't see how it's necessary)
Or you could use this syntax
nextPic = () => {
this.setState({i: this.state.i++});
}
backPic = () => {
this.setState({i: this.state.i--});
}
There are lots of mistakes you made, look at my code and compare yours. Hope you can find the error.
class App extends Component {
constructor(props) {
super(props);
this.state = {
i: 0
};
var hinhanh = ["1.png", "2.png", "3.png"];
this.nextPic = this.nextPic.bind(this);
this.backPic = this.backPic.bind(this);
}
componentDidMount() {
this.setState({ anh: this.state.i});
}
nextPic() {
this.setState({ i: this.state.i++ });
console.log(this.state.i);
}
backPic() {
this.setState({ i: this.state.i-- });
console.log(this.state.i);
}
render(){
return(
<div>
<img src={this.state.anh}/>
<br/>
<button onClick={this.nextPic}>Next</button>
<button onClick={this.backPic}>Back</button>
</div>
)
}
}
You can define state property immediately into state like this this.state = { i: 0, j: this.state.i}, herejis undefined. So you need to use life cycle methodcomponentDidMounttosetState`.
You need to bind your functions, otherwise you need to use arrow function like this, nextPic = () => {//function defination}

isOpen from Leaflet not respond the new status

I try to use the event .isOpen does not update its status when I click on my popup.
Someone know why or know how to do ?
This is my code :
class Map extends React.Component {
constructor(props) {
super(props);
this.state = {
x: 0,
y: 0,
geojsonData: null,
geojsonData6: null,
}
}
initMap() {
//Declaration of the map
var valMarker = L.marker([this.state.y, this.state.x]).addTo(this.state.map)
.bindPopup('Hotel "Port de Calais"<br> 7 circuits à proximités.')
var valPopup = valMarker.getPopup()
if (valPopup.isOpen() === true) {
var myData = [this.state.geojsonData, this.state.geojsonData6]
L.geoJSON(myData).addTo(this.state.map)
}
}
componentDidMount() {
this.initData(2985).then((data) => {
this.setState({geojsonData: JSON.parse(data[0].geojson)})
});
//and more
this.initData(4661).then((data) => {
this.setState({geojsonData6: JSON.parse(data[0].geojson)})
this.initMap()
});
}
render() {
<Map />
return <div id="map" style={style} />;
}
}
I think, I need to do something in render(), but I don't find actually the solution.
Of course, when I do "marker.openPopup();" before the .isOpen(), the condition is true. But I want a action from the user?
Thanks !

The most "react" way to pass state to other components

I am fairly new to React. Currently I have two React components - Article.js and ControlForm.js
My render return in Article.js is this:
return (
<div className="article">
{article_wrapper.map( article =>
<div key={article.node.nid} className="article-main-display">
<h1 className="title" dangerouslySetInnerHTML={createMarkup(article.node.title)}/>
<div className="img-div"><img src={article.node.field_image.src} /></div>
<ControlForm />
<div dangerouslySetInnerHTML={createMarkup(article.node.field_user_hsk_level)} />;
<div className="field-name-field-chinese">
<div dangerouslySetInnerHTML={createMarkup(article.node.chinese)} />;
</div>
</div>
)}
</div>
);
The ControlForm.js has several form elements (all of which I'd like to be able to pass along if need be), but this is the main one:
<div className="form-item form-type-select form-group">
<label className="control-label">Font Size</label>
<select
value={this.state.value}
onChange={this.handleSizeSelect}
id="font-size"
className="form-control form-select"
>
<option value="0">Small</option>
<option value="1">Normal</option>
<option value="2">Large</option>
<option value="3">XL</option>
</select>
</div>
I'd like to be able to set a class on one of the divs in the Article.js based on changing a value in the ControlForm.js
What is the most "React" way to do this? Would creating a common parent to both be the best method (right now, their only parent in common is the main App.js)
Sorry if I don't totally understand how this is supposed to work - this is my first React app.
The class associated with the components are ControlForm and withFetching respectively.
EDIT - the demo example below works, but I have some additional issues with how to integrate it properly into my existing code. Here's the existing functions of ControlForm:
class ControlForm extends Component {
constructor() {
super();
this.state = { toggleActive: false, sizeSelect: "0", speed: 1.3, volume: .6};
this.onToggle = this.onToggle.bind(this);
this.handleSpeedChange = this.handleSpeedChange.bind(this);
this.handleVolumeChange = this.handleVolumeChange.bind(this);
this.handleSizeSelect = this.handleSizeSelect.bind(this);
}
onToggle() {
this.setState({ toggleActive: !this.state.toggleActive });
}
handleSizeSelect(event) {
this.setState({ sizeSelect: event.target.value });
this.setState({font: 'large-font'});
parentMethod(event.target.value);
}
handlePlayClick(e) {
e.preventDefault();
voice.playButtonClick();
}
handlePauseClick(e) {
e.preventDefault();
voice.pauseButtonClick();
}
handleStopClick(e) {
e.preventDefault();
voice.stopButtonClick();
}
handleVolumeChange(event) {
console.log(event.target.value);
this.setState({ volume: event.target.value });
}
handleSpeedChange(event) {
console.log(event.target.value);
this.setState({ speed: event.target.value });
}
Articles looks like this:
const withFetching = (url) => (Comp) =>
class WithFetching extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: false,
error: null,
dynamicClassName: "parentClass"
};
this.changeClassName = this.changeClassName.bind(this);
}
changeClassName(childData) {
this.setState({
dynamicClassName: childData
});
}
componentDidMount() {
this.setState({ isLoading: true });
fetch(url)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong ...');
}
})
.then(data => this.setState({ data, isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }));
}
render() {
//return "test";
return <Comp { ...this.props } { ...this.state } />
}
}
function createMarkup(html) {
return {__html: html};
}
function changeClassName(childData) {
console.log("GETS HERE!")
this.setState({
dynamicClassName: childData
});
}
const Articles = ({ data, isLoading, error }) => {
console.log(data);
console.log(isLoading);
const article_wrapper = data.nodes || [];
if (error) {
return <p>{error.message}</p>;
}
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<div className="article">
{article_wrapper.map( article =>
<div key={article.node.nid} className="article-main-display">
<h1 className="title" dangerouslySetInnerHTML={createMarkup(article.node.title)}/>
<div className="img-div"><img src={article.node.field_image.src} /></div>
<ControlForm parentMethod={changeClassName} />
<div dangerouslySetInnerHTML={createMarkup(article.node.field_user_hsk_level)} />;
<div className="field-name-field-chinese">
<div dangerouslySetInnerHTML={createMarkup(article.node.chinese)} />;
</div>
</div>
)}
</div>
);
}
export default withFetching(API)(Articles);
Sorry about all of these questions, I know a lot of this is due to unfamiliarity with React - this is the first thing I've tried to build in React
You want to change parents from his childs.
First, you have to create a handler function at Article.js and pass it to ControlForm.js as a property.
<ControlForm changeDiv={this.changeDiv} />
Then you focus on ControlForm.js, whenever you want to happen, you just execute the function you passed as a the prop changeDiv, like this.props.changeDiv()
See also possible duplicate: How to update parent's state in React?
you can conditionally render a class based on state and your handler was missing the values from the event on the onChange
here's a demo of dynamically changing style base on the state
demo
Article.js ,
class Article extends React.Component {
constructor(props) {
super(props);
this.state = {
dynamicClassName: "parentClass"
}
this.changeClassName = this.changeClassName.bind(this);
}
changeClassName(childData) {
this.setState({
dynamicClassName: childData
});
}
// user dynamicClassName wherever u want .
return ( <
div className = "article" > {
article_wrapper.map(article =>
<
div key = {
article.node.nid
}
className = "article-main-display" >
<
h1 className = "title"
dangerouslySetInnerHTML = {
createMarkup(article.node.title)
}
/> <
div className = "img-div" > < img src = {
article.node.field_image.src
}
/></div >
<
ControlForm parentMethod={this.changeClassName} / >
<
div dangerouslySetInnerHTML = {
createMarkup(article.node.field_user_hsk_level)
}
/>; <
div className = "field-name-field-chinese" >
<
div dangerouslySetInnerHTML = {
createMarkup(article.node.chinese)
}
/>; < /
div > <
/div>
)
} <
/div>
);
}
In ControlForm js ,
class ControlForm extends React.Component {
constructor(props) {
super(props);
this.state = {
}
this.handleSizeSelect= this.handleSizeSelect.bind(this);
}
handleSizeSelect() {
this.props.parentMethod(this.state.value);
}
render() {
return (
<div className="form-item form-type-select form-group">
<label className="control-label">Font Size</label>
<select
value={this.state.value}
onChange={this.handleSizeSelect}
id="font-size"
className="form-control form-select"
>
<option value="0">Small</option>
<option value="1">Normal</option>
<option value="2">Large</option>
<option value="3">XL</option>
</select>
</div>
);
}
}

pass props to dynamic child component

I am trying to create a multiple step form. I have created the form where in each step, corresponding form is rendered dynamically. But I have no idea on how should I pass props to those component so that when returning back, the state gets preserved. I have created a sandbox of it in codesandbox and here it is
https://codesandbox.io/s/8xzm2mxol2
The rendering of form is done the following way
{this.props.steps[this.state.componentState].component}
If the component is rendered as below which is static way, the code would be something like this but I want the dynamic way
if(this.state.componentState === 1) {
<Form1 props={props} />
}
The code is
import React from 'react';
import './fullscreenForm.css';
class MultipleForm extends React.PureComponent {
constructor(props) {
super(props);
this.hidden = {
display: "none"
};
this.state = {
email: 'steve#apple.com',
fname: 'Steve',
lname: 'Jobs',
open: true,
step: 1,
showPreviousBtn: false,
showNextBtn: true,
componentState: 0,
navState: this.getNavStates(0, this.props.steps.length)
};
}
getNavStates(indx, length) {
let styles = [];
for (let i = 0; i < length; i++) {
if (i < indx) {
styles.push("done");
} else if (i === indx) {
styles.push("doing");
} else {
styles.push("todo");
}
}
return { current: indx, styles: styles };
}
checkNavState(currentStep) {
if (currentStep > 0 && currentStep < this.props.steps.length) {
this.setState({
showPreviousBtn: true,
showNextBtn: true
});
} else if (currentStep === 0) {
this.setState({
showPreviousBtn: false,
showNextBtn: true
});
} else {
this.setState({
showPreviousBtn: true,
showNextBtn: false
});
}
}
setNavState(next) {
this.setState({
navState: this.getNavStates(next, this.props.steps.length)
});
if (next < this.props.steps.length) {
this.setState({ componentState: next });
}
this.checkNavState(next);
}
next = () => {
this.setNavState(this.state.componentState + 1);
};
previous = () => {
if (this.state.componentState > 0) {
this.setNavState(this.state.componentState - 1);
}
};
render() {
return (
<div className="parent-container">
<div className="form-block">
{this.props.steps[this.state.componentState].component}
</div>
<div
className="actions"
style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'flex-end'}}
>
<button
style={this.state.showPreviousBtn ? {} : this.hidden}
className="btn-prev"
onClick={this.previous}
>
Back
</button>
<button
style={this.state.showNextBtn ? {} : this.hidden}
className="btn-next"
onClick={this.next}
>
Continue
</button>
</div>
</div>
);
}
}
export default MultipleForm;
I wanted it in best practice way.
You need to save the values of your form for all the step inputs. Now since on every step you are changing the form component, so you cannot put those values in corresponding form component. Therefore you have to put those values in the parent container (i.e. MultipleForm). Now as you are maintaining a state of values of your child component in parent container, therefore you will have to put some kind of mechanism so that whenever there is any change in input in child component, it should update the corresponding state in parent container. For that you can pass a change handler function to you child component. So your form component should look something like this
<div className="fullscreen-form">
<div className="custom-field">
<label className="custom-label fs-anim-upper" for="email">
What's your email address?
</label>
<input
className="fs-anim-lower"
id="email"
name="email"
type="email"
onChange={this.props.handleChange} // Whenver the input changes then call the parent container's handleChange function so that it can update it's state accordingly
value={this.props.value} // Updated value passed from parent container
placeholder="steve#apple.com"
/>
</div>
</div>
And you will render your form something like this
<Form1 handleChange={this.handleChange} value={this.state.email} />
Here's a working solution of your code:: Code

Go to previous state in reactjs

I'm building a component which proceeds according to the selections of the users. I have completed it successfully but facing some issues when trying to implement a back button to go back.
My code is like follows.
class ReportMainCat extends Component {
constructor(props) {
super(props);
this.state = {
postType: null,
}
this.changeType = this.changeType.bind(this);
this.report_next = this.report_next.bind(this);
};
report_next() {
if (this.state.postType == null) {
return <ReportFirst changeType={this.changeType}/>
}
else if (this.state.postType === 'sexual') {
return <ReportXContent changeType={this.changeType}/>
} else if (this.state.postType === 'selfharm') {
return <ReportThreatContent changeType={this.changeType}/>
}
}
changeType = (postType) => {
this.setState({postType})
this.setState({
showMainReportCats: false,
})
}
render() {
return (
<div className="top_of_overlay">
<div className="section_container text_align_center padding_10px">
<a className="">Report Category</a>
{this.report_next()}
</div>
</div>
)
}
}
I'm binding the postType value as follows.
class ReportXContent extends Component {
constructor(props) {
super(props);
this.state = {
postType: '',
}
};
textType(postType) {
this.props.changeType(postType);
}
render() {
return (
<div className="text_align_left">
<div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="nudity" onClick={this.textType.bind(this,'nudity')}/>
<a>Nudity or Pornography</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="minor" onClick={this.textType.bind(this,'minor')}/>
<a>Includes Minors</a>
</div>
</div>
<ReportButtons/>
</div>
)
}
}
My back button
<div>
<button className="float_right margin_left5px" onClick={this.props.back_report}>Back</button>
</div>
So basically what i'm trying to do is this.
Ex: If the user selects postType as sexual it will return the ReportXContent component. How can i return to the first page when the user clicks the back button.
Thanks.
You could implement the back button click handler like this in the ReportMainCat component:
handleBackClick() {
this.setState({ postType: null });
}
, and that would show the ReportFirst view again.
If you don't want the first view, but the last view, simply change your changeType implementation to save lastPostType to state like this:
changeType = (postType) => {
this.setState({
lastPostType: this.state.postType,
postType,
showMainReportCats: false,
});
}
Edit
If you want full history of changes - let's say if you want to implement a full back button history - you can simply rename lastPostType to postTypeHistory and implement it like a stack (like the browser history is):
changeType = (postType) => {
this.setState({
postTypeHistory: [...this.state.postTypeHistory, this.state.postType],
postType,
showMainReportCats: false,
});
}
handleBackClick() {
const { postTypeHistory } = this.state;
const postType = postTypeHistory.pop();
this.setState({
postType,
postTypeHistory,
});
}

Categories