why setState does'nt change the "editing" key to true? - javascript

The edit function does not change the editing in state to true.
I don't know what to do:
class Note extends React.Component {
constructor (props) {
super(props)
this.state = {
editing: false
}
}
/**edit() {
this.setState = ({
editing: true
})**/
}
remove() {
alert ("removed")
}
save() {
alert ("saved")
}
renderForm() {
return (
<div className="note">
<form>
<textarea/>
<button onClick={this.save}> click </button>
</form>
</div>
)
}
renderDisplay() {
return (
<div className="note">
<p> Learn React </p>
<span>
<button onClick={this.edit} id="edit"> Edit </button>
<button onClick={this.remove} id="remove"> Delete </button>
</span>
</div>
)
}
render() {
return this.state.editing ? this.renderForm() : this.renderDisplay()
}
}

You should change this:
this.setState = ({
editing: true
})
to this:
this.setState({
editing: true
})
Also, you should bind edit method or use an arrow function instead. It's required because in JavaScript function context is defined while calling the function, not while defining it.
Here you can check an example.

Related

Creating show and hide sections with buttons in reactjs

I have three buttons that when clicking show and individual div but this is done in reactjs
import React, { Component } from 'react';
export class ModeExtended extends Component {
constructor() {
super();
this.busButton = this.busButton.bind(this);
this.trainButton = this.trainButton.bind(this);
this.tramButton = this.tramButton.bind(this);
this.state = {
isHidden: false,
}
}
busButton(){
console.log('Bus Button Was Pressed');
this.setState((prevState) => {
return{
isHidden: !prevState.isHidden
};
});
}
trainButton(){
console.log('Train Button Was Pressed');
this.setState((prevState) => {
return{
isHidden: !prevState.isHidden
};
});
}
tramButton(){
console.log('Tram Button Was Pressed');
this.setState((prevState) => {
return{
isHidden: !prevState.isHidden
};
});
}
render() {
return (
<div>
<h5>Mode Extended</h5>
<button onClick={this.busButton}>Bus</button>
<button onClick={this.trainButton}>Train</button>
<button onClick={this.tramButton}>Tram</button>
{this.state.isHidden && (
<div>
<h6>You can show Bus Data Now....</h6>
</div>
)}
{this.state.isHidden && (
<div>
<h6>You can show Train Data Now....</h6>
</div>
)}
{this.state.isHidden && (
<div>
<h6>You can show Tram Data Now....</h6>
</div>
)}
</div>
)
}
}
export default ModeExtended
When I click any of the buttons it shows all bus, tram and train data - how do I get them to just show one thing at a time and making sure that the other states are closed. I am really missing something here and need a pointer or two or three…
How can I add an ID to make each button open separate from each other and when one is clicked how can I close the rest of the divs - or open state, I am so lost here. Please help me out.
Cheers as always!
Here is a REPL of my code:
You need to have 3 different isHidden properties to control your divs. You can do it like this:
this.state = {
isHiddenBus: false,
isHiddenTrain: false,
isHiddenTram: false,
}
and then in your render like this:
{this.state.isHiddenBus && (
<div>
<h6>You can show Bus Data Now....</h6>
</div>
)}
{this.state.isHiddenTrain && (
<div>
<h6>You can show Train Data Now....</h6>
</div>
)}
{this.state.isHiddenTram && (
<div>
<h6>You can show Tram Data Now....</h6>
</div>
)}
also your buttons have to change to state accordingly to this.
busButton(){
console.log('Bus Button Was Pressed');
this.setState((prevState) => {
return{
isHiddenBus: !prevState.isHiddenBus
isHiddenTram: false
isHiddenTrain: false
};
});
}
trainButton(){
console.log('Train Button Was Pressed');
this.setState((prevState) => {
return{
isHiddenTrain: !prevState.isHiddenTrain
isHiddenBus: false
isHiddenTram: false
};
});
}
tramButton(){
console.log('Tram Button Was Pressed');
this.setState((prevState) => {
return{
isHiddenTram: !prevState.isHiddenTram
isHiddenTrain: false
isHiddenBus: false
};
});
}
you can do somthing like this:
import React, { Component } from 'react';
export class ModeExtended extends Component {
constructor() {
super();
this.state = {
curDivIndex:0,//currently visible div index
// isHidden: false,
}
}
renderDiv=()=>{
switch(this.state.curDivIndex){
case 1:return <div> <h6>You can show Bus Data Now....</h6> </div>
case 2:return <div> <h6>You can show Train Data Now....</h6> </div>
case 3:return <div> <h6>You can show Tram Data Now....</h6> </div>
}
return null
}
setVisibleDiv=(index)=>{
this.setState({curDivIndex:index})
}
render() {
return (
<div>
<h5>Mode Extended</h5>
<button onClick={()=>{this.setVisibleDiv(1)} }>Bus</button>
<button onClick={()=>{this.setVisibleDiv(2)}}>Train</button>
<button onClick={()=>{this.setVisibleDiv(3)}}>Tram</button>
{this.renderDiv()}
</div>
)
}
}
export default ModeExtended
EDIT
you want to have three different buttons, on click of each certain div
needs to be visible.
you can achieve this by maintaining the index of currently visible div.
when user clicks any button you have to set the index of div to be visible
which in the above code is achieved by using setVisibleDiv(index) call.
and you can at rendering time use curDivIndex to decide visible div.
Or you can achieve this by declaring state properties for all case:
this.state = {
hiddenBus: false,
hiddenTrain: false,
hiddenTram: false,
}
providing a name attribute to your buttons like so:
<button name="hiddenBus" onClick={toggleDisplay}>Bus</button>
<button name="hiddenTrain" onClick={toggleDisplay}>Train</button>
<button name="hiddenBus" onClick={toggleDisplay}>Tram</button>
then by defining the toggleDisplay function to toggle their display:
toggleDisplay = (event) => {
event.preventDefault(); // default behavior of a clicked button is to send a form so let's prevent this
const { name } = event.target; // find the clicked button name value
this.setState((prevState => ({
[name]: !prevState[name],
}));
}
Setting[name] enables us to target the state prop via the nameattribute value and update it based on the previous state.
Try this
import React, { Component } from "react";
export default class Create extends Component {
constructor(props) {
super(props);
this.state = {
currentBtn: null
};
}
clickedButton = e => {
this.setState({ currentBtn: e.target.id });
};
showDivElem = () => {
const { currentBtn } = this.state;
switch (currentBtn) {
case "A":
return <div>A</div>;
break;
case "B":
return <div>B</div>;
break;
case "C":
return <div>C</div>;
break;
default:
return <div>ABC</div>;
break;
}
};
render() {
console.log(this.state.currentBtn);
return (
<div>
<button id="A" onClick={e => this.clickedButton(e)}>
A
</button>
<button id="B" onClick={e => this.clickedButton(e)}>
B
</button>
<button id="C" onClick={e => this.clickedButton(e)}>
C
</button>
{this.showDivElem()}
</div>
);
}
}

bind(this) in ReactJS and onChange update to state

I have the following code:
index.js
class App extends React.Component {
constructor() {
super();
this.state = {
homeLink: "Home"
};
}
onGreet() {
alert("Hello!");
}
onChangeLinkName(newName) {
this.setState({
homeLink: newName
});
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
<Header homeLink={this.state.homeLink}/>
</div>
</div>
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
<Home
name={"Max"}
initialAge={27}
greet={this.onGreet}
changeLink={this.onChangeLinkName.bind(this)}
initialLinkName={this.state.homeLink}
/>
</div>
</div>
</div>
);
}
}
And
Home.js
export class Home extends React.Component {
constructor(props) {
super();
this.state = {
age: props.initialAge,
status: 0,
homeLink: props.initialLinkName
};
}
onMakeOlder() {
this.setState({
age: this.state.age + 3
});
}
onChangeLink() {
this.props.changeLink(this.state.homeLink);
}
onHandleChange(event) {
this.setState({
homeLink: event.target.value
});
}
render() {
return (
<div>
<p>In a new Component!</p>
<p>Your name is {this.props.name}, your age is {this.state.age}</p>
<p>Status: {this.state.status}</p>
<hr/>
<button onClick={() => this.onMakeOlder()} className="btn btn-primary">Make me older!</button>
<hr/>
<button onClick={this.props.greet} className="btn btn-primary">Greet</button>
<hr/>
<input type="text" value ={this.state.homeLink}
onChange={(event) => this.onHandleChange(event)}/>
<button onClick={this.onChangeLink.bind(this)} className="btn btn-primary">Change Header Link</button>
</div>
);
}
}
Would onChange in the input tag be triggered as soon as I write something in the input field and update to state? I can't see the state change in the React Developer Tool extension in Chrome when I write something in the input field.
When I click the button this.onChangeLink it triggers the onChangeLink function. The onChangeLink doesn't seem to take any arguments since the brakets are empty, still I'm able to pass this.state.homeLink to this.props.changeLink inside the onChangeLink function. this.props.changeLink which is also a function in index.js takes an argument newName. I guess this is where the bind(this) comes in. What does bind(this) do? Could I rewrite it with a fat arrow function like (event) => this.onChangeLink(event)?
bind is a function in Function.prototype which returns a function object which is bound to the current this.
onClick={this.onChangeLink.bind(this)}
Here onClick function will be passed as a handler with the current context.
An arrow function does not create a new this context at all. The this will refer to the context in which the function is defined.
An arrow function does not create its own this context, so this has its original meaning from the enclosing context.
onChange={(event) => this.onChangeLink(event)}
Here even though onChangeLink is not bound, it is called within an arrow function within the same this context.
So.. yes, you can replace it with a fat arrow notation to get the same effect. Although you have to rewrite the list of arguments in this case twice.
You dont need to onChangeLink in Home component. You can directly pass the value to App component.
class Home extends React.Component {
constructor(props) {
super();
this.state = {
age: props.initialAge,
status: 0,
homeLink: props.initialLinkName
};
}
onMakeOlder() {
this.setState({
age: this.state.age + 3
});
}
onHandleChange(event) {
this.setState({
homeLink: event.target.value
});
}
render() {
return (
<div>
<input type="text" value ={this.state.homeLink}
onChange={(event) => this.onHandleChange(event)}/>
<button onClick={()=>this.props.changeLink(this.state.homeLink)} className="btn btn-primary">Change Header Link</button>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
homeLink: "Home"
};
}
onGreet() {
alert("Hello!");
}
onChangeLinkName(newName) {
this.setState({
homeLink: newName
});
}
render() {
console.log(this.state)
return (
<div className="container">
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
</div>
</div>
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
<Home
name={"Max"}
initialAge={27}
greet={this.onGreet}
changeLink={this.onChangeLinkName.bind(this)}
initialLinkName={this.state.homeLink}
/>
</div>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"))
<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="app"></div>

React - How to show relative div when mouse hover on a html tag?

Below is my code...
<ul className="no-style board__list">
{Object.keys(today.books).map(function(id) {
var refBook = today.books[id][0];
return (
<li key={refBook._id} className="board__list-item">
<div className="container flexrow">
<div className="flexrow__fit-2">{refBook.book_no}</div>
<div className="flexrow__org">
<span className="board__icon-wrap">
{refBook.memo
? (<i className="fa fa-flag" style={{color:"#F9AB9F"}}></i>)
: null
}
</span>
{refBooking.memo
? (<div className="memo_dialog">{refBook.memo}</div>)
: null
}
</div>
</div>
</li>
);
})}
</ul>
I have a object books array and I create a fa-flag icon for each book.
What I want is to show different memo dialog when mouse hover on each flag icon.
I know how to do it with query but how can I do this in react way not using jquery?
I'm not sure what are you trying to achieve but this example might be useful for you
class Book extends React.Component {
constructor(props){
super(props);
this.handleOver = this.handleOver.bind(this);
}
handleOver(name){
this.props.over(this.props.name)
}
render(){
return <div onMouseOver={this.handleOver}>{this.props.name}</div>
}
}
class BookList extends React.Component {
constructor(props){
super(props);
this.mouseOver = this.mouseOver.bind(this);
this.state = {
books: ['hello', 'amazing', 'world'],
memo: ''
}
}
mouseOver(name){
this.setState({memo: name})
}
render(){
const bookList = this.state.books.map((book, index)=>{
return <Book key={index} name={book} over={this.mouseOver}/>
});
return <div>
{bookList}
<hr/>
<div>{this.state.memo}</div>
</div>
}
}
React.render(<BookList />, document.getElementById('container'));
Also fiddle example.
I hope it will help you. Thanks
I suggest you to use isHovered state variable, to store hover state.
We are displaying some component(in your case it would be dialog box), if isHovered is true and hide it when this variable is false.
When we will hover on link element, we will trigger handleEnter function to set isHovered variable to true.
Similarly, when we are moving cursor out of link element, we are triggering handleLeave function to set isHovered variable to false.
Example:
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
isHovered: false,
};
}
handleEnter() {
this.setState({
isHovered: true
});
}
handleLeave() {
this.setState({
isHovered: false
});
}
render() {
return (
<div>
<a
onMouseEnter={this.handleEnter.bind(this)}
onMouseLeave={this.handleLeave.bind(this)}
>Link</a>
{this.state.isHovered ? (
<div className="box">A component</div>
) : (
<div />
)}
</div>
);
}
}
Also, you can see demo at CodePen.

react show button on mouse enter

I have a react component which hold method like:
mouseEnter(){
console.log("this is mouse enter")
}
render(){
var album_list;
const {albums} = this.props
if(albums.user_info){
album_list = albums.user_info.albums.data.filter(album => album.photos).map((album => {
return
<div className={"col-sm-3"} key={album.id} onMouseEnter={this.mouseEnter}>
<div className={(this.state.id === album.id) ? 'panel panel-default active-album' : 'panel panel-default'} key={album.id} onClick={this.handleClick.bind(this, album.id)}>
<div className={"panel-heading"}>{ album.name }</div>
<div className={"panel-body"}>
<img className={"img-responsive center-block"} src={album.photos.data[0].source} />
</div>
</div>
</div>
}))
}
return (
<div className={"container"}>
<div className="row">
{album_list}
</div>
</div>
)
}
}
Here I have onMouseEnter on album_list. When it is hover or mouse enter I want to dispalay a button on that div.
How can I do that ??
Thank you
Update the component's state to reflect whether the mouse is inside the component, then use the state value to conditionally render a button.
getInitialState() {
return {
isMouseInside: false
};
}
mouseEnter = () => {
this.setState({ isMouseInside: true });
}
mouseLeave = () => {
this.setState({ isMouseInside: false });
}
render() {
return (
<div onMouseEnter={this.mouseEnter} onMouseLeave={this.mouseLeave}>
{this.state.isMouseInside ? <button>Your Button</button> : null}
</div>
);
}
Inside the render function we use the conditional operator (?) to return the button component if this.state.isMouseInside is truthy.
There is another approach that uses a reusable render component that would make components 'hoverable' or 'revealable' - whatever makes sense.
class Hoverable extends Component {
constructor() {
super();
this.state = {
isMouseInside: false
};
}
mouseEnter = () => {
this.setState({ isMouseInside: true });
}
mouseLeave = () => {
this.setState({ isMouseInside: false });
}
render() {
return this.props.children(
this.state.isMouseInside,
this.mouseEnter,
this.mouseLeave
)
}
}
Then create the functional component that represents the hoverable element. E.g an album
const HoverableElement = props => (
<Hoverable>
{(isMouseInside, mouseEnter, mouseLeave) => (
<div className="menu-item">
<div onMouseEnter={mouseEnter} onMouseLeave={mouseLeave}>
<h2>{props.title}</h2>
</div>
{isMouseInside && props.children}
</div>
)}
</Hoverable>
)
Finally, use the HoverableElement to render a list of elements that will each be 'hoverable' e.g an array of albums
class HoverableElementsList extends Component {
render() {
return (
<div>
<HoverableElement title="First Menu">
<p>Some children content</p>
</HoverableElement>
</div>
)
}
}

React - Cannot read property 'call' of undefined

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 = () => {}

Categories

Resources