this.transformer.anchorSize is not a function - javascript

I was trying to make some changes in Transformer Component in React Konva and faced this error whenever I was trying to change anchor size. I followed the syntax as stated in document - https://konvajs.github.io/api/Konva.Transformer.html#validateAnchors__anchor
The issue is in anchorSize. Please help me. Here's the code -
class TransformerComponent extends React.Component {
componentDidMount () {
this.checkNode ();
}
componentDidUpdate () {
this.checkNode ();
}
checkNode() {
const stage = this.transformer.getStage();
const { selectedShapeName } = this.props;
const selectedNode = stage.findOne ('.' + selectedShapeName);
this.transformer.rotateEnabled (false);
this.transformer.anchorSize (5);
if (selectedNode === this.transformer.node()) {
return;
}
if (selectedNode) {
this.transformer.attachTo (selectedNode);
}
else {
this.transformer.detach();
}
this.transformer.getLayer().batchDraw();
}
render() {
return (
<Transformer
ref = {node => {
this.transformer = node;
}}
/>
);
}
}

anchorSize is a very new property introduces recently. Try to update Konva to the latest version.

You need to bind this for checkNode() as down below:
class TransformerComponent extends React.Component {
constructor(props) {
super(props)
this.checkNode = this.checkNode.bind(this)
}
...

Related

How to call child's method from parent without using Refs?

Let's say I've a parent component A and a child B:
A:
class A {
constructor() {
this.state = {data: []};
}
handleClick = () => {
// api call
// set data state to the returned value from api
// call B's createTable method
}
render() {
return(
<div>
<button onClick={()=> this.handleClick()}>Fetch data</button>
<B data={this.state.data} />
</div>
}
}
B:
class B {
constructor() {
this.state = {...};
}
createTable = () => {
const { data } = this.props;
// do smth
}
render() {
return(...);
}
}
I want to call createTable method from A without using Refs.
What I've done so far is using componentDidUpdate life cycle method in B to check if data prop has changed or not, If it changed call createTable method but I want to know is this right? or there's a better way of doing it because I feel it is kinda hacky or maybe bad design.
class B {
constructor() {
this.state = {...};
}
componentDidUpdate(prevProps) {
const { data } = this.props;
if (data !== prevProps.data) {
this.createTable();
}
}
createTable = () => {
const { data } = this.props;
// do smth
}
render() {
return(...);
}
}
NOTE I don't want to use hooks either just class based component.
The following example might be useful
class Parent extends Component {
render() {
return (
<div>
<Child setClick={click => this.clickChild = click}/>
<button onClick={() => this.clickChild()}>Click</button>
</div>
);
}
}
class Child extends Component {
constructor(props) {
super(props);
this.getAlert = this.getAlert.bind(this);
}
componentDidMount() {
this.props.setClick(this.getAlert);
}
getAlert() {
alert('clicked');
}
render() {
return (
<h1 ref="hello">Hello</h1>
);
}
}

How to make the background image change every X seconds in React?

FINAL EDIT:
See working code below:
import React, { Component } from 'react';
var images = [
"https://www.royalcanin.com/~/media/Royal-Canin/Product-Categories/cat-adult-landing-hero.ashx",
"https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_March_2010-1.jpg"
]
class App extends Component {
constructor(props) {
super(props);
this.state = { imgPath: "url(" + images[1] + ")" };
}
componentDidMount() {
this.interval = setInterval(() => {
this.setState({ imgPath: "url(" + images[0] + ")" })
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div className="App">
<div className='dynamicImage' style={{ backgroundImage: this.state.imgPath }} >
{console.log(this.state.imgPath)}
</div>
</div >
);
}
}
ORIGINAL THREAD:
I'm trying to use setInterval() to change the image dynamically every X seconds.
I just don't understand where setInterval is supposed to be placed within the code, or what its output is supposed to be.
My current code is:
import React, { Component } from 'react';
// Paths to my images
var images = [
"https://www.royalcanin.com/~/media/Royal-Canin/Product-Categories/cat-adult-landing-hero.ashx",
"https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_March_2010-1.jpg"
]
var imgPath = "url(" + images[1] + ")" // Set original value of path
function f1() {
imgPath = "url(" + images[0] + ")" // Change path when called ?
}
class App extends Component {
render() {
setInterval(f1, 500); // Run f1 every 500ms ?
return (
<div className="App">
<div className='dynamicImage' style={{ backgroundImage: imgPath }} > // Change background image to one specified by imgPath
</div>
</div >
);
}
}
export default App;
The current code outputs the first imgPath's URL, but fails to update it to the one specified within the function f1. To the best of my knowledge, the function f1 does appear to run, as removing it, or setting an undefined variable does return an error. I just can't get it to change imgPath.
Any ideas on what I'm doing wrong, or how I could improve my code?
Cheers
Edit: Commented code + removed unnecessary lines
I would move all your variables into your component and as Akash Salunkhe suggests, use componnentDidMount to setInterval. Don't forget to clear the interval when the component unmounts.
This answer will also work with using any number of images.
class App extends React.Component {
constructor(props) {
super(props);
const images = [
"https://www.royalcanin.com/~/media/Royal-Canin/Product-Categories/cat-adult-landing-hero.ashx",
"https://www.petfinder.com/wp-content/uploads/2013/09/cat-black-superstitious-fcs-cat-myths-162286659.jpg",
"https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_March_2010-1.jpg"
];
this.state = {
images,
currentImg: 0
}
}
componentDidMount() {
this.interval = setInterval(() => this.changeBackgroundImage(), 1000);
}
componentWillUnmount() {
if (this.interval) {
clearInterval(this.interval);
}
}
changeBackgroundImage() {
let newCurrentImg = 0;
const {images, currentImg} = this.state;
const noOfImages = images.length;
if (currentImg !== noOfImages - 1) {
newCurrentImg = currentImg + 1;
}
this.setState({currentImg: newCurrentImg});
}
render() {
const {images, currentImg} = this.state;
const urlString = `url('${images[currentImg]}')`;
return (
<div className="App">
<div className='dynamicImage' style={{backgroundImage: urlString}} >
</div>
</div >
);
}
}
You might want to use this.props or this.state to store the imgPath, otherwise React doesn't know you have changed anything.
Put image path in state and in componentDidMount, use setInterval and inside it use setState to change image path.
#Anurag is correct. You need to use setInterval in componentDidMount and ensure that you call this.setState if you want the render method to rerender. This of course requires that you store the image path in this.state
You can create an endless loop similar to this, you might want to use an array of image urls and write some logic for that. But as you can see I have an endless loop created for the function setImage():
constructor(props) {
super();
this.state = {
image1: props.imageUrls[0],
image2: props.imageUrls[1],
changeImage: true
};
this.setImage();
}
setImage() {
setTimeout(() => {
this.setState({ changeImage: !this.state.changeImage }, this.setImage());
}, 3000);
}
You need to use componentDidMount() React Lifecycle method to register your setInterval function.
Here is a working example
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
images: [
"https://picsum.photos/200/300/?image=523",
"https://picsum.photos/200/300/?image=524"
],
selectedImage: "https://picsum.photos/200/300/?image=523"
};
}
componentDidMount() {
let intervalId = setInterval(() => {
this.setState(prevState => {
if (prevState.selectedImage === this.state.images[0]) {
return {
selectedImage: this.state.images[1]
};
} else {
return {
selectedImage: this.state.images[0]
};
}
});
}, 1000);
this.setState({
intervalId
});
}
componentWillUnmount() {
clearInterval(this.state.intervalId);
}
render() {
return (
<div className="App">
<img src={this.state.selectedImage} alt={"images"} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You can change around the code and can find live demo here:
https://codesandbox.io/s/0m12qmvprp

React load value and allow user to alter value within component

I'm new to React (16.4.2), and I'm trying to understand the way it works. I don't want to complicate things with redux; I just want to know about the core react library.
I have an application, and (eventually down the children chain) there is an input, which is a component, RangeInput. It's just a wrapper component for an input.
The problem is two parts
I should be able to change the value within the range (as a user)
if there is data in the local storage, it should load it the first time. This also means that the user should still be able to alter/change the input value.
Right now with this, I see to only be able to do one of the other. I know I'm not understanding something here.
What needs to happen?
Thanks,
Kelly
Here are the classes:
export class RangeInput extends React.Component {
constructor(props) {
super(props);
this.ds = new DataStore();
this.state = {
value: props.value
};
}
static getDerivedStateFromProps(props, state) {
console.log('props', props, 'state', state);
if (props.value !== state.value) {
return {value: props.value};
}
return null;
}
onChange(event) {
const target = event.target;
this.setState({
value: target.value
});
if (this.props.onChange) {
this.props.onChange({value: target.value});
}
}
onKeyUp(event) {
if (event.keyCode !== 9) {
return;
}
const target = event.target;
if (this.props.onChange) {
this.props.onChange({value: target.value});
}
}
render() {
return <div>
<input type="number" value={this.state.value}
onChange={this.onChange.bind(this)}
onKeyUp={this.onKeyUp.bind(this)}/>
</div>;
}
}
const DATA_LOAD = 'load';
export class Application extends React.Component {
constructor() {
super();
this.state = {
value: -1,
load = DATA_LOAD
};
}
componentDidMount() {
if (this.state.load === DATA_LOAD) {
this.state.load = DATA_CLEAN;
const eco = this.ds.getObject('the-app');
if (eco) {
this.setState({value: eco});
}
}
}
render(){
return <RangeInput value={this.state.value} />;
}
}
ReactDOM.render(
<Application/>,
document.getElementById('root')
);
I think this situation can be simplified quite a bit:
import React from 'react';
export const RangeInput = props => (
<input
value={props.value}
onChange={props.setValue} />
)
export class Application extends React.Component {
constructor(props) {
super(props);
this.state = { value: -1, };
}
componentDidMount() {
var val = localStorage.getItem('myVal');
if (val) this.setState({value: val})
}
setValue(e) {
this.setState({value: e.target.value})
localStorage.setItem('myVal', e.target.value);
}
render() {
return <RangeInput
value={this.state.value}
setValue={this.setValue.bind(this)} />;
}
}
Here we have two components: <RangeInput>, a stateless component, and <Application>, the brains behind the operation.
<Application> keeps track of the state, and passes a callback function to RangeInput. Then, on keydown, <RangeInput> passes the event object to that callback function. Application then uses the event object to update the state and the localStorage. On refresh, the last saved value is fetched from localStorage and present in the input (if available).

set class using state if else with react gets state of undefined error

I'm trying to set a class dynamically depending on the pros i send to the component. Somehow i get the error " Cannot read property 'state' of undefined".
I guess that this doesn't exist when i try to set the class of the state as a class? Do i have to rebind it before i use it in the render of the component?
var ReactDOM = require('react-dom');
var React = require('react');
class Button extends React.Component {
constructor(props) {
super(props);
console.log("BUTTON")
console.log(props);
this.state = {
class: "small-button"
};
props.options.map(function (option) {
if (option.Description > 10) {
this.setState({
class: "big-button"
});
}
});
console.log("STATE: " + this.state.class);
}
render() {
if (this.props.options) {
return (<div> {
this.props.options.map(function (option) {
return <div className={ this.state.class === 'big-button' ? 'option-button big-button' : 'option-button small-button'} key={option.Id}> {option.Description}</div>
})
}
</div>
)
} else {
return <div>No options defined</div>
}
}
}
module.exports = Button;
It's a binding issue, you need to bind the function to use this keyword (correct context) inside that.
Use this:
render() {
if (this.props.options) {
return (<div> {
this.props.options.map((option) => {
return <div className={ this.state.class === 'big-button' ? 'option-button big-button' : 'option-button small-button'} key={option.Id}> {option.Description}</div>
})
}
</div> )
} else {
return <div>No options defined</div>
}
}
Check this answer for more detail on arrow function and this keyword
One Suggestion: Don't put logic inside constructor and don't do setState also, use lifecycle method for that. Put that logic inside componentDidMount method or componentWillMount method.
Like this:
class Button extends React.Component {
constructor(props) {
super(props);
this.state = {
class: "small-button"
};
}
componentDidMount(){
this.props.options.forEach((option) => {
if (option.Description > 10) {
this.setState({
class: "big-button"
});
}
});
}
render() {
if (this.props.options) {
return (
<div>
{
this.props.options.map((option) => {
return <div className={ this.state.class === 'big-button' ? 'option-button big-button' : 'option-button small-button'} key={option.Id}> {option.Description}</div>
})
}
</div>
)
}else{
return <div>No options defined</div>
}
}
}

ES6 - Warning: setState(…): Cannot update during an existing state transition

I am rewriting some old ReactJS code, and got stuck fixing this error (the error repeats about 1700 times in the console, the DOM does not render at all):
Warning: setState(...): Cannot update during an existing state
transition (such as within render or another component's
constructor). Render methods should be a pure function of props and
state; constructor side-effects are an anti-pattern, but can be moved
to componentWillMount.
I am a Component that passes it's state down to a component that should render some controls. Based on the clicked controls, the state should change, and new controls should render.
So this is my Container component:
class TeaTimer extends Component {
constructor(props) {
super(props);
this.state = {
count: 120,
countdownStatus: 'started'
}
}
componentDidUpdate(prevProps, prevState) {
if (this.state.countdownStatus !== prevState.countdownStatus) {
switch (this.state.countdownStatus) {
case 'started':
this.startTimer();
break;
case 'stopped':
this.setState({count:0});
}
}
}
componentWillUnmount() {
clearInterval(this.timer);
delete this.timer;
}
startTimer() {
this.timer = setInterval(() => {
let newCount = this.state.count -1;
this.setState({
count: newCount >= 0 ? newCount : 0
});
if(newCount === 0) {
this.setState({countdownStatus: 'stopped'});
}
}, 1000)
}
handleStatusChange(newStatus) {
this.setState({ countdownStatus: newStatus });
}
render() {
let {count, countdownStatus} = this.state;
let renderStartStop = () => {
if (countdownStatus !== 'stopped') {
return <StartStop countdownStatus={countdownStatus} onStatusChange={this.handleStatusChange()}/>
} else {
return <div>This will be the slider form</div>
}
};
return(
<div className={styles.container}>
<p>This is the TeaTimer component</p>
<Clock totalSeconds={count}/>
{renderStartStop()}
</div>
)
}
}
And this is my controls component:
class StartStop extends Component {
constructor(props) {
super(props);
}
onStatusChange(newStatus) {
return() => {
this.props.onStatusChange(newStatus);
}
}
render() {
let {countdownStatus} = this.props;
let renderStartStopButton = () => {
if(countdownStatus === 'started') {
return <button onClick={()=> this.onStatusChange('stopped')}>Reset</button>;
} else {
return <button onClick={()=> this.onStatusChange('started')}>Start</button>
}
};
return(
<div className={styles.tt.Controls}>
{renderStartStopButton()}
</div>
)
}
}
StartStop.propTypes = {
countdownStatus: React.PropTypes.string.isRequired,
onStatusChange: React.PropTypes.func.isRequired
};
I am sorry about the wall of text, but I really can;t figure out where the error is coming from - and therefor don't know which part of the code I can leave out.
I have tried implementing the solution found in a seemingly related question, but can't get it to work either.
I think you have a typo in this line:
return <StartStop countdownStatus={countdownStatus} onStatusChange={this.handleStatusChange()}/>
It should be:
return <StartStop countdownStatus={countdownStatus} onStatusChange={() => this.handleStatusChange}/>
You seem to be calling the method handleStatusChange instead of passing it as a callback.
Your metods call each other so you must define two instance of your metods.
class StartStop extends Component {
constructor(props) {
super(props);
this.onStatusChangeReset=this.onStatusChange.bind(this);
this.onStatusChangeStart=this.onStatusChange.bind(this);
}
onStatusChange(newStatus) {
return() => {
this.props.onStatusChange(newStatus);
}
}
render() {
let {countdownStatus} = this.props;
let renderStartStopButton = () => {
if(countdownStatus === 'started') {
return <button onClick={this.onStatusChangeReset('stopped')}>Reset</button>;
} else {
return <button onClick={this.onStatusChangeStart('started')}>Start</button>
}
};
return(
<div className={styles.tt.Controls}>
{renderStartStopButton()}
</div>
)
}
}
StartStop.propTypes = {
countdownStatus: React.PropTypes.string.isRequired,
onStatusChange: React.PropTypes.func.isRequired
};
In this line in your return <StartStop countdownStatus={countdownStatus} onStatusChange={this.handleStatusChange()}/> gives the warning, the handleStatusChanged function is called on pressing a button which tries to change the state by setState keyword. whenever the state is changed render function is called again but in your case render function was in progress of returning while the render function is called again by setState keyword.

Categories

Resources