React issue with composition - _constructComponentWithoutOwner [duplicate] - reactjs

Everything seems to work with this small app except adding a new note. Button is located on the Board component.
i know this problem is usually caused by not binding value of 'this' properly. I'm not sure if that's the issue here or if i'm missing something else. Thanks
Demo: http://jsbin.com/pewahi/edit?js,output
/* jshint asi:true */
class Note extends React.Component {
constructor(props) {
super(props)
this.state = { editing: props.editing }
}
render() {
if (this.state.editing) {
return this.renderForm()
} else {
return this.renderDisplay()
}
}
edit() {
this.setState({editing: true})
}
save() {
this.props.changeHandler(this.refs.newText.getDOMNode().value, this.props.index)
this.setState({editing: false})
}
remove() {
this.props.removeHandler(this.props.index)
}
renderDisplay() {
return (
<div className="note">
<p>{this.props.children}</p>
<span>
<button className="btn btn-sm glyphicon glyphicon-pencil" onClick={this.edit.bind(this)}></button>
<button className="btn btn-sm glyphicon glyphicon-trash" onClick={this.remove.bind(this)}></button>
</span>
</div>
)
}
renderForm() {
return (
<div className="note">
<textarea ref="newText" defaultValue={this.props.children} className="form-control"></textarea>
<button onClick={this.save.bind(this)} className="btn btn-success btn-sm"><span className="glyphicon glyphicon-floppy-disk"></span> Save</button>
</div>
)
}
}
Note.propTypes = {
editing: React.PropTypes.bool,
onChange: React.PropTypes.func,
onRemove: React.PropTypes.func
}
Note.defaultProps = { editing: false }
class Board extends React.Component {
constructor(props) {
super(props)
this.state = {
notes: [{note: 'hi', id: this.nextId()}]
}
}
update(newText, i) {
var arr = this.state.notes
arr[i].note = newText
this.setState({notes: arr})
}
remove(i) {
var arr = this.state.notes
arr.splice(i, 1)
this.setState({notes: arr})
}
addNote(text) {
var arr = this.state.notes
arr.push({
id: this.nextId(),
note: text
})
console.log(arr)
this.setState({notes: arr})
}
nextId() {
this.uniqueId = this.uniqueId || 0
return ++this.uniqueId
}
eachNote(note, i) {
return (
<Note key={note.id}
index={i}
changeHandler={this.update.bind(this)}
removeHandler={this.remove.bind(this)}
>{note.note}
</Note>
)
}
render() {
return (
<div className="board">
{this.state.notes.map(this.eachNote, this)}
<button onClick={this.addNote.bind(this, "new note")} className="btn btn-success btn-sm glyphicon glyphicon-plus"></button>
</div>
)
}
}
React.render(
<Board />,
document.getElementById('message-board')
)

Your code is fine. This is likely a bug with JSBin, and how it handles transpilation with Babel. If you add the pragma // noprotect to the top of your code you will see that it works.

I was facing the same error. I was using a base component and I noticed that I had removed componentDidMount method of the base component. And when I call super.componentDidMount in sub component it was giving the error. So I have removed super call and problem solved.

Binding this is something of a hassle with ES6 classes in React. One way is to bind them in your constructor like so;
constructor(props) {
super(props)
this.nextid = this.nextid.bind(this)
this.state = {
notes: [{note: 'hi', id: this.nextId()}]
}
}
Another is to use babel.configure({stage: 0}) and arrow functions.
nextid = () => {}

Related

How do I call an event for another component in React?

I've been working in react for about.. 2 days. 3/4's of that was me trying to get react to work with my current Asp.net MVC WebApp.
I have 2 classes. Everything is working fine, but I want the handleScan of Camera to call the handleHideClick() of ShowScanner. Whats the proper way to do that?
Here is my code:
import React from 'react';
import QrReader from 'react-qr-reader';
import { unmountComponentAtNode, render } from "react-dom";
class Camera extends React.Component {
state = {
result: 'No result'
}
handleScan = data => {
if (data) {
this.setState({
result: data
});
scanDataProcessor(this.state.result);
unmountComponentAtNode(document.getElementById('root'));
// *** Replace unmount above with a call to execute: ShowScanner.handleHideClick()
}
}
handleError = err => {
console.error(err)
}
render() {
return (
<div id="scanner" class="">
<QrReader
delay={300}
onError={this.handleError}
onScan={this.handleScan}
style={{ width: '100%' }}
/>
</div>
)
}
}
class ShowScanner extends React.Component {
constructor(props) {
super(props);
this.handleShowClick = this.handleShowClick.bind(this);
this.handleHideClick = this.handleHideClick.bind(this);
this.state = { showCamera: false }
}
handleShowClick() {
this.setState({ showCamera: true });
render(<Camera />, document.getElementById('root'));
}
handleHideClick() {
this.setState({ showCamera: false });
unmountComponentAtNode(document.getElementById('root'));
}
render() {
const showCamera = this.state.showCamera;
let button;
if (showCamera) {
return (
<button id="btnScan" type="button" class="btn btn-primary p-1" onClick={this.handleHideClick}>
<i class="bi bi-qr-code-scan"></i>
<br />Scan
</button>
);
} else {
return (
<button id="btnScan" type="button" class="btn btn-primary p-1" onClick={this.handleShowClick}>
<i class="bi bi-qr-code-scan"></i>
<br />Scan
</button>
);
}
}
}
render(<ShowScanner />, document.getElementById('scanBtn'));
At the very least, I need to reset the button so that when they click it, it remounts the Camera component without them having to click it twice.
Thanks in advance!

How to pass methods with parameters to children in React? (Cannot read property 'props' of undefined)

I'm currently making a to-do list, but unfortunately ran into some errors where I am unable to pass methods to a child component.
const React = require('react');
class App extends React.Component {
constructor(props){
super(props)
this.state = {
items: [],
input: ""
}
this.inputChange = this.inputChange.bind(this);
this.addItems = this.addItems.bind(this);
this.remItems = this.remItems.bind(this);
}
inputChange(event){
this.setState({
input: event.target.value
})
}
addItems(){
event.preventDefault()
const temp = this.state.input
this.setState({
input: "",
items: this.state.items.concat(temp)
})
}
remItems(id){
const temp = [...this.state.items]
const updatedItems = temp.filter(item => item.id!==id)
this.setState({
items: updatedItems
})
}
render(){
return (
<div class = "w-100 p-3">
<p>Enter your item here:</p>
<form onSubmit = {this.addItems} class="form.inline">
<input class = "form.control mb-2 mr-sm-2" value = {this.state.input} onChange = {this.inputChange}/>
<button type="submit" class="btn btn-primary mb-2">Add</button>
</form>
<UnorderedList items={this.state.items} remove = {this.remItems}/>
</div>
);
}
}
class UnorderedList extends React.Component {
constructor(props){
super(props)
}
render(){
return (
<ul>
{this.props.items.map(function(item, i) {
return (<div id = "entry" class = "d-flex">
<li key={i}>{item}</li>
{console.log(i)}
<button class = 'btn btn-sm btn-primary ml-auto' onClick = {() => this.remItems}> Done! </button>
</div>)
})}
</ul>
)
}
}
I expected to be able to remove the items by id key but it gives me "Cannot read property 'props' of undefined". Thanks for your help!

How to remove an element in reactjs by an attribute?

I want to get unknown key attribute using known ID so that i may delete corresponding div.
I tried using document.getElementById("a").getAttribute('key'); , but it isn't working. May be my concept is wrong.
class PostAdded extends Component {
constructor(props) {
super();
this.deletepost = this.deletepost.bind(this);
}
deletepost() {
let ab =document.getElementById("a").getAttribute('key');
console.log(ab)
}
render() {
return (
<div>
{ this.props.posts.map((post, i) =>
<div id="a" key={`i-${post.title}`}>
<span> <h3>{post.title}</h3><p>{post.post}</p></span>
<input type="button" value="Delete" onClick={this.deletepost}/>
</div>
) }
</div>
)
}
}
export default PostAdded;
If you were able to delete the div, that probably wouldn't end up working for you anyway because any state change would cause a re-render and it would appear again. Instead, you could keep track of your posts in state and then remove one of the posts from state in your deletepost method.
class PostAdded extends Component {
constructor(props) {
super();
this.state = {
posts: props.posts
}
this.deletepost = this.deletepost.bind(this);
}
deletepost(index) {
const newPosts = this.state.posts.splice(index)
this.setState({posts: newPosts})
}
render() {
return (
<div>
{ this.state.posts.map((post, i) =>
<div id="a" key={`i-${post.title}`}>
<span> <h3>{post.title}</h3><p>{post.post}</p></span>
<input type="button" value="Delete" onClick={() => this.deletepost(i)}/>
</div>
) }
</div>
)
}
}
export default PostAdded;

Reactjs multiple form submit

In my case, i would like to submit multiple forms in reactjs. But i have no idea on how to get the multiple form at Parent Component and submit.
here is my code:
class BulkEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [],
customCompanies: []
};
this.forms = [];
this.onAddChild = this.onAddChild.bind(this);
this.handleBulkSaveClick = this.handleBulkSaveClick.bind(this);
}
handleBulkSaveClick(event) {
event.preventDefault();
}
/*
* -- Add Children
*/
onAddChild() {
this.state.items.push(BulkEditorForm.defaultProps);
this.setState({
items: this.state.items
});
}
render() {
var forms = this.state.items.map(function(item, index) {
return (
<li className="list-group-item" key={index}>
<BulkEditorForm companies={this.state.customCompanies} item={item}
ref="editorform"></BulkEditorForm>
</li>
);
}.bind(this));
return (
<ul className="list-group">
{forms}
<li className="list-group-item">
<div className="btn-group btn-group-sm pull-right" role="group" aria-label="bulk-buttons">
<a href="javascript:;" className="btn btn-primary" onClick={this.onAddChild.bind(this)}>
<span className="glyphicon glyphicon-plus"></span>
</a>
<a href="javascript:;" className="btn btn-default" onClick={this.handleBulkSaveClick}>Bulk Save</a>
</div>
<div className="clearfix"></div>
</li>
</ul>
);
}
}
Here is next class
export default class BulkEditorForm extends React.Component {
constructor(props) {
super(props);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleFormSubmit(event) {
event.preventDefault();
alert("Submit");
}
render() {
return (
<form action='#' method="post" onSubmit={this.handleFormSubmit}>
<button type="submit" className="btn btn-link">Save</button>
</form>
);
}
}
In your loop of rendering form list, use different ref value for each form:
<BulkEditorForm companies={this.state.customCompanies} item={item}
ref={"editorform"+index}></BulkEditorForm>
Then after all forms are rendered, access the form list by refs in your Parent Component, which means adding componentDidMount() function as follows:
class BulkEditor extends React.Component {
constructor(props) {
}
componentDidMount() {
//using basic javascript "FOR" loop ^^
for (i = 0; i < this.state.items.length; i++) {
this.forms.push(this.refs["editorform"+index]);
}
}
}
I didn't have time for testing all the code, but that's the idea! If it doesn't work yet, feel free to post here some error logs, then we may solve it together, thanks ^^

onClick in reactjs not working

Below is my code. My onClick is nor working. It always through error "Uncaught TypeError: Cannot read property 'likeQuestion' of undefined". But my "gotoPage" function is working. I don't know where I am wrong. I am very new in Reactjs. Why "likeQuestion" function is not recognized.
My first onClick is working
export default class Question extends React.Component {
constructor(){
super();
this.toggle = this.toggle.bind(this);
this.state = {
pageNo : 1,
dropdownOpen: false,
questioninfo : []
}
}
componentWillMount(){
//some action
}
gotoPage(index) {
//some action. This is working
}
toggle() {
this.setState({
dropdownOpen: !this.state.dropdownOpen
});
}
likeQuestion(e){
console.log('this is clicked');
//But this is not working
}
render() {
var canvases = this.state.questionItem.map(function(data,i) {
var firstLtr = data.user_name.charAt(0);
return (
<div key={i}>
<Col sm="12" md={{ size: 12, offset: 2 }} className="questionCard">
<Card block>
<CardTitle>
<div className="outerCircle"><span>{firstLtr}</span></div> {data.user_name}
<i className="fa fa-flag-o flagging" aria-hidden="true"></i>
{data.location_url}
</CardTitle>
<CardText className="questionTxt">{data.message}</CardText>
<div>
<Button className="replyBtn" disabled>No Discussion</Button>
<Button size="sm" color="link" className="disussionSpan" onClick={(i) => this.likeQuestion(i)}>{data.likes} Likes</Button>
</div>
</Card>
</Col>
</div>
);
});
return(
<div className="container">
<div className="row">
<div className="pageInfo">
<Dropdown className="inline" isOpen={this.state.dropdownOpen} toggle={this.toggle}>
<DropdownToggle caret>
Pages
</DropdownToggle>
<DropdownMenu>
{pgrow}
</DropdownMenu>
</Dropdown>
<p className="inline currPgNo">Page: {currentPage}</p>
</div>
<div className="col-md-8 col-md-offset-2">
{canvases}
</div>
</div>
</div>
)
}
React wouldn't auto-bind map inside render(), so you have to do it yourself in order to use this and call this.likeQuestion. Luckily, map provides a second argument to specify the context (this).
So just use...
this.state.questionItem.map(function(data,i) {
...
}, this)
instead of
this.state.questionItem.map(function(data,i) {
...
})
Option 2: Use arrow function in the map, such as map((data, i) => ...
Option 3: bind this to likeQuestion in the constructor of the component.
Try to define your helper functions using arrow functions
gotoPage = (index) => {
//some action. This is working
}
toggle = () => {
this.setState({
dropdownOpen: !this.state.dropdownOpen
});
}
likeQuestion = (e) => {
console.log('this is clicked');
//But this is not working
}
or
Bind these methods in constructor of your React component. e.g
this.likeQuestion = this.likeQuestion.bind(this);
// Needs to be done for all the helper methods.
So that you access the class level this context.
E.g a minimal setup
class Question extends React.Component {
constructor(props) {
super(props);
this.state = {
likes:10
};
}
likeQuestion = (e) => {
console.log('this is clicked');
//But this is not working
}
render() {
return ( < div >
< button size = "sm"
color = "link"
className = "disussionSpan"
onClick = {
(i) => this.likeQuestion(i)
} > {
this.state.likes
}
Likes < /button>
< /div >
);
}
};
ReactDOM.render( < Question / > , document.querySelector('#test'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="test">
</div>

Resources