How change onMouseMove handler in other handler with react component? - javascript

How we can change the handlerOnMouseMove inside other handler (in my example OnClick).
I show an example below;
normally when I do this this.handleMouseMove = undefined; it should disable my event onMouseMove but unfortunately it is not working.
import React from 'react'
import {render} from 'react-dom'
import './BasicComponent.css'
class BasicComponent extends React.Component {
constructor (props){
super(props)
this.state = {
id: "id",
title: "component",
inputs: [],
outputs: [],
}
this.handleClick = this.handleClick.bind(this)
this.handleMouseDown = this.handleMouseDown.bind(this)
this.handleMouseUp = this.handleMouseUp.bind(this)
this.handleMouseMove = this.handleMouseMove.bind(this)
}
render() {
console.log("render");
return(
<div className="component"
onMouseDown={ this.handleMouseDown }
onMouseUp={ this.handleMouseUp }
onMouseMove={ this.handleMouseMove }>
<div className="title">Title</div>
<div className="id">ID: c_356545454</div>
<div className="inputs">inputs</div>
<div className="core">core</div>
<div className="outputs">outputs</div>
<button onClick={ this.handleClick } >Disable handler onMouseMove</button>
</div>
);
}
handleClick() {
this.handleMouseMove = undefined; // <===== this not disable the call on handleMouseMove ???
console.log("handleClick : handleMouseMove is disabled");
}
handleMouseDown() {
console.log("handleMouseDown");
}
handleMouseUp() {
console.log("handleMouseUp");
}
handleMouseMove() {
console.log("handleMouseMove");
}
}
export default BasicComponent

Try this:
class BasicComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
id: "id",
title: "component",
inputs: [],
outputs: [],
disableMouseMove: false,
};
this.handleClick = this.handleClick.bind(this);
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this.handleMouseMove = this.handleMouseMove.bind(this);
}
render() {
const { disableMouseMove } = this.state;
return (
<div
className="component"
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
onMouseMove={disableMouseMove ? () => {} : this.handleMouseMove}
>
<div className="title">Title</div>
<div className="id">ID: c_356545454</div>
<div className="inputs">inputs</div>
<div className="core">core</div>
<div className="outputs">outputs</div>
<button onClick={this.handleClick}>Disable handler onMouseMove</button>
</div>
);
}
handleClick() {
this.setState({ disableMouseMove: true }); // <===== this not disable the call on handleMouseMove ???
console.log("handleClick : handleMouseMove is disabled");
}
}

You can createRef for the wrapper div you are tracking the "mousemove", add the "mousemove" event listener for that ref once component mounts and remove it once the button is clicked. Hint, there is no more "onMouseMove" for the wrapping div. Below I also replaced your class methods with arrow functions in order to avoid binding them.
export default class BasicComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
id: "id",
title: "component",
inputs: [],
outputs: [],
}
this.myRef = React.createRef()
}
componentDidMount(){
this.myRef.current.addEventListener('mousemove', this.handleMouseMove)
}
handleClick = () => {
this.myRef.current.removeEventListener('mousemove', this.handleMouseMove)
console.log("handleClick : handleMouseMove is disabled");
}
handleMouseDown = () => {
console.log("handleMouseDown");
}
handleMouseUp = () => {
console.log("handleMouseUp");
}
handleMouseMove = () => {
console.log("handleMouseMove");
}
render() {
console.log("render");
return (
<div ref={this.myRef} className="component"
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
>
<div className="title">Title</div>
<div className="id">ID: c_356545454</div>
<div className="inputs">inputs</div>
<div className="core">core</div>
<div className="outputs">outputs</div>
<button onClick={this.handleClick} >Disable handler
onMouseMove
</button>
</div>
);
}
}

Related

React JS : grandparent component's setState method doesn't update state of a grandchild input field onChange event click

In the same code, I was able to the get the grandparent component's setState method to update accordingly for an onClick event from the grandchild component, however, for the onChange event, it is failing. I am not getting any errors.
class GrandChild extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
changeNumber=()=> {
this.props.changeNumber();//call child method
}
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
const data = this.props.data;
return(
<div>
<h1>The number is {this.props.number}</h1>
<input type="text" value = {data} onChange={this.handleChange} />
<button onClick={this.changeNumber}>Increase number by 1</button>
</div>
)
}
}
class Child extends React.Component {
render() {
return(
<div>
<GrandChild number={this.props.number} changeNumber={this.props.changeNumber} value={this.props.data} onChange={this.props.handleChange}/>
</div>
)
}
}
class App extends React.Component {
constructor() {
super()
this.state = {
number: 1,
data: ""
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(data) {
this.setState({data:this.state.data});
console.log(data);
}
changeNumber=()=>{
this.setState((prevState)=>{
console.log(prevState,this.state.data);
return {
number : prevState.number + 1
}
});
}
render() {
const data = this.state.data;
const input = data;
return (
<Child number={this.state.number}
changeNumber = {this.changeNumber}
data={input}
onChange = {this.handleChange}
/>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Console Result:
Object {
data: "",
number: 1
} ""
result screenshot:
console.log result
see code pen for live code:
https://codepen.io/codehorse/pen/yLyEwBw?editors=0011
Your improved code with live demo https://codesandbox.io/s/laughing-sky-kk97b
What need to change <GrandChild number={this.props.number} changeNumber={this.props.changeNumber} value={this.props.data} onChange={this.props.onChange}/>
Complete Code
class GrandChild extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
changeNumber = () => {
this.props.changeNumber(); //call child method
};
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
const data = this.props.data;
return (
<div>
<h1>The number is {this.props.number}</h1>
<input type="text" value={data} onChange={this.props.onChange} />
<button onClick={this.changeNumber}>Increase number by 1</button>
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
<GrandChild
number={this.props.number}
changeNumber={this.props.changeNumber}
value={this.props.data}
onChange={this.props.onChange}
/>
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 1,
data: ""
};
}
handleChange = e => {
this.setState({ data: e.target.value });
console.log(e.target.value);
};
changeNumber = () => {
this.setState(prevState => {
console.log(prevState, this.state.data);
return {
number: prevState.number + 1
};
});
};
render() {
const data = this.state.data;
const input = data;
return (
<Child
number={this.state.number}
changeNumber={this.changeNumber}
data={input}
onChange={this.handleChange}
/>
);
}
}
export default App;

Not showing any text when clicked on the button in reactjs

I am trying to implement in toggle button feature where when clicking on button willshowtext and clicking on button again willhidetext.
When i tried implement this i am stuck at displaying the text . I used the below for showing the text
import React, { Component } from "react";
export default class DisplayStats extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
console.log('Click happened');
<div>HELLO</div>
}
render() {
return (
<div className="container">
<h1>This is the stats.</h1>
<button onClick={this.handleClick}>Click Me</button>
</div>
)
}
}
With this i can see the console.log is created but i cant able to see the HELLO when i clicked on the button.
Am i missing anything here ?
Any help is appreciated
Thanks
You cannot return an element from an event handler and have it render like that.
You need to hide the text behind a flag and then toggle that flag.
First we create a flag in state. This defines if the toggle text should be displayed.
this.state = {
showText: false // Should the text be displayed?
};
Next we update the click handler to toggle that state flag.
this.setState((state) => ({
showText: !state.showText // Toggle showText
}))
Finally we conditionally render the toggle text. If showText is true, then render the text, if it is false do not render it.
{this.state.showText && <div>HELLO</div>}
Optional:
As pointed out by Mosè Raguzzini you do not need to bind your event handler.
this.handleClick = this.handleClick.bind(this); // This is not needed
handleClick = () => {} // because this is an arrow function
All together now:
import React, { Component } from "react";
export default class DisplayStats extends Component {
constructor(props) {
super(props);
this.state = {
showText: false // Should the text be displayed?
};
}
handleClick = () => {
console.log('Click happened');
this.setState((state) => ({
showText: !state.showText // Toggle showText
}))
}
render() {
return (
<div className="container">
<h1>This is the stats.</h1>
{this.state.showText && <div>HELLO</div>}
<button onClick={this.handleClick}>Click Me</button>
</div>
)
}
}
You should change state on toggle.
import React, { Component } from "react";
export default class DisplayStats extends Component {
state = {
isToggled : false
}
constructor(props) {
super(props);
}
handleClick = () => {
console.log('Click happened');
this.setState({isToggled : !this.state.isToggled});
}
render() {
return (
<div className="container">
<h1>This is the stats.</h1>
<button onClick={this.handleClick}>Click Me</button>
</div>
{(() => {
if(this.state.isToggled){
return <div>HELLO</div>
}
else{
return <div></div>
}
})()}
)
}
}
You do not need to use bind if you already use arrow functions, beside this, you have to learn how to manage state:
import React, { Component } from "react";
export default class DisplayStats extends Component {
constructor(props) {
super(props);
this.state = {
displayedText: '',
}
}
handleClick = () => {
console.log('Click happened');
this.setState({ displayedText: 'This is my text.'});
}
render() {
return (
<div className="container">
<h1>This is the stats. {this.state.displayedText}</h1>
<button onClick={this.handleClick}>Click Me</button>
</div>
)
}
}
To achieve this, you'll want to track state in your component to determine if the text should be displayed or not. The following code should achieve what you're after:
export default class DisplayStats extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
console.log('Click happened');
// When the button is clicked, the text display state is toggled
this.setState({ showText : !this.state.showText })
}
render() {
// Extract state to determine if the text should be shown
const showText = !!this.state.showText
return (
<div className="container">
{ /* Render div with text is showState is truthy /* }
{ showText && <div>HELLO</div> }
<h1>This is the stats.</h1>
<button onClick={this.handleClick}>Click Me</button>
</div>
)
}
}
That is not how react and other state based frameworks work. The idea is that the view should change when the state changes and only state can cause any change in the view. What you would need to do is on click of button, change the state which in turn will cause your view to update
import React, { Component } from "react";
export default class DisplayStats extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
visible: false
}
}
handleClick = () => {
this.setState({visible: !this.state.visible});
}
render() {
return (
<div className="container">
<h1>This is the stats.</h1>
<button onClick={this.handleClick}>Click Me</button>
{ this.state.visible ? <div>Hello</div> : '' }
</div>
)
}
}

onClick props in template.js not triggering

Why is onClick={this.onToggleMenuModal} not triggering on div id="freezer", whilst it is in my components by passing onToggleMenuModal={this.handleToggleMenuModal}?
Adding onToggleMenuModal={this.handleToggleMenuModal} to returned an error of Unknown Prop Warning
Here is the code...
import React from 'react';
import PropTypes from 'prop-types';
...
class Template extends React.Component {
constructor(props) {
super(props)
this.state = {
menuModal: false,
loading: 'is-loading'
}
this.handleToggleMenuModal = this.handleToggleMenuModal.bind(this)
}
componentDidMount () {
this.timeoutId = setTimeout(() => {
this.setState({loading: ''});
}, 100);
}
componentWillUnmount () {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
}
handleToggleMenuModal() {
this.setState({
menuModal: !this.state.menuModal
})
}
render() {
const { children } = this.props
return (
<div id="perspective" className={`showMenu ${this.state.loading} ${this.state.menuModal ? 'animate modalview' : ''}`}>
<Helmet>
...
</Helmet>
<div id="container">
<Header onToggleMenuModal={this.handleToggleMenuModal} />
<div id="wrapper">
{children()}
<Footer />
</div>
<div id="freezer" onClick={this.onToggleMenuModal}></div>
</div>
</div>
)
}
}
Template.propTypes = {
children: PropTypes.func,
}
export default Template
You must put onClick inside arrow fuction like :
onClick={() => {this.onToggleMenuModal}}
Check this solution and let me know if it work for you or not.
import React from 'react';
import PropTypes from 'prop-types';
...
class Template extends React.Component {
constructor(props) {
super(props)
this.state = {
menuModal: false,
loading: 'is-loading'
}
this.handleToggleMenuModal = this.handleToggleMenuModal.bind(this)
}
componentDidMount () {
this.timeoutId = setTimeout(() => {
this.setState({loading: ''});
}, 100);
}
componentWillUnmount () {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
}
}
handleToggleMenuModal() {
this.setState({
menuModal: !this.state.menuModal
})
}
render() {
const { children } = this.props
return (
<div id="perspective" className={`showMenu ${this.state.loading} ${this.state.menuModal ? 'animate modalview' : ''}`}>
<Helmet>
...
</Helmet>
<div id="container">
<Header onToggleMenuModal={this.handleToggleMenuModal} />
<div id="wrapper">
{children()}
<Footer />
</div>
<div id="freezer" onClick={this.onToggleMenuModal}></div>
</div>
</div>
)
}
}
Template.propTypes = {
children: PropTypes.func,
}
export default Template

Why is a horizontal line created, when user inputs whitespace?

This is my code. When I'm trying to run it, for empty spaces as input it is creating a horizontal line.
import React, { Component } from 'react';
export default class App extends Component {
constructor(props) {
super(props);
this.state = { items: [], text: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
render() {
return (
<div>
<form onSubmit = {this.handleSubmit}>
<input
onChange={this.handleChange}
value={this.state.text />
</form>
<div>
<TodoList items={this.state.items} />
</div>
</div>
);
}
handleChange(e) {
this.setState({ text: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.text.length) {
return;
}
const newItem = {
text: this.state.text,
};
this.setState(prevState => ({
items: prevState.items.concat(newItem),
text: ''
}));
}
}
class TodoList extends React.Component {
render() {
return (
<div>
{this.props.items.map(item => (
<h3 key={item.id}>{item.text}</h3>
))}
</div>
);
}
}
Your code will always append a <h3> element even with whitespace as input.
And you're seeing a horizontal line probably due to the CSS styling applied to
h3.
What you can do it prevent users from inserting whitespace data. One approach is to trim() user's input before doing length checking:
// In handleSubmit()
if (!this.state.text.trim().length) {
return;
}
Now input with only whitespace will become 0 length and therefore exit handleSubmit() earlier.
import React, { Component } from 'react'
class TodoList extends React.Component {
render() {
return (
<div>
{ this.props.items.map(item => <h3 key={ item.id }>{ item.text }</h3>) }
</div>
);
}
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = { items: [], text: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ text: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.text.trim().length) {
return;
}
const newItem = {
text: this.state.text,
};
this.setState(prevState => ({
items: prevState.items.concat(newItem),
text: ''
}));
}
render() {
return (
<div>
<form onSubmit={ this.handleSubmit }>
<input onChange={ this.handleChange } value={ this.state.text }/>
</form>
<div>
<TodoList items={ this.state.items } />
</div>
</div>
)
}
}

React Fetch Request

I was trying to change the site to which I do the fetch request when I click the button Next in the App component, passing the other site
<FilterableProductTable getSite={ this.state.active ? '/get_platfo
rms' : '/get_features' } />
but it is not working, it shows just the old information. I think is some asynchronous problem
export class FilterableProductTable extends React.Component {
constructor(props) {
super(props);
this.state = {
posts: []
};
}
fetch() {
axios.get(this.props.getSite)
.then(res => {
this.setState({
posts: res.data.functionality
});
});
}
componentDidMount() {
this.fetch();
setTimeout(function(){this.fetch();} , 5000);
}
render() {
return (
<div>
<ProductTable products={this.state.posts} />
</div>
);
}
}
export class App extends React.Component {
constructor(props){
super(props);
this.state= {active: true};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
active: !prevState.active
}));
}
render() {
return (
<div>
<FilterableProductTable getSite={ this.state.active ? '/get_platforms' : '/get_features' } />
<a className={ this.state.active ? 'button' : 'hidden' } onClick={this.handleClick}><span>Next</span></a>
</div>
);
}
}
try this code:
export class FilterableProductTable extends React.Component {
constructor(props) {
super(props);
this.state = {
posts: []
};
}
fetch() {
axios.get(this.props.getSite)
.then(res => {
this.setState({
posts: res.data.functionality
});
});
}
componentDidUpdate(){
this.fetch();
}
componentDidMount() {
this.fetch();
setTimeout(function(){this.fetch();} , 5000);
}
render() {
return (
<div>
<ProductTable products={this.state.posts} />
</div>
);
}
}
export class App extends React.Component {
constructor(props){
super(props);
this.state= {active: true};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
let newState = !this.state.active;
this.setState({
active: newState
});
}
render() {
return (
<div>
<FilterableProductTable getSite={ this.state.active ? '/get_platforms' : '/get_features' } />
<a className={ this.state.active ? 'button' : 'hidden' } onClick={this.handleClick}><span>Next</span></a>
</div>
);
}
}
Changes from your version: caught componentDidUpdate event(if the component updated fetch is called) and changed the handleClick method. Let me know if this fixes your problem.

Categories