react-hotkeys cntrl+s while focus is in textarea - javascript

I am trying to be able to use cntrl+s while focus within a textarea using react-hotkeys.
this.keyMap = {
KEY: "ctrl+s"
};
this.handlers = {
KEY: (e) => {
e.preventDefault();
this.saveBtn(c);
}
};
<HotKeys keyMap={this.keyMap} handlers={this.handlers}>
<textarea/>
</HotKeys>

You need to use Control+s, not ctrl+s.
You need to call configure like that so it won't ignore textareas:
import { configure } from "react-hotkeys";
configure({
ignoreTags: []
});

Following is not solution it's work around but it fulfills the requirement...
[Please Note] Basically I have restricted access to Ctrl key in browser and then it
works fine though.
import { HotKeys } from 'react-hotkeys';
import React, { PureComponent, Component } from 'react';
import { configure } from 'react-hotkeys';
const COLORS = ['green', 'purple', 'orange', 'grey', 'pink'];
const ACTION_KEY_MAP = {
KEY: 'Control+s',
};
class Login extends Component {
constructor(props, context) {
super(props, context);
this.changeColor = this.changeColor.bind(this);
configure({
ignoreTags: ['div']
});
this.state = {
colorNumber: 0
};
}
changeColor(e) {
e.preventDefault();
this.setState(({ colorNumber }) => ({ colorNumber: colorNumber === COLORS.length - 1 ? 0 : colorNumber + 1 }));
}
KeyDown(e){
if(e.ctrlKey) e.preventDefault();
}
render() {
const handlers = {
KEY: this.changeColor
};
const { colorNumber } = this.state;
const style = {
width: 200,
height: 60,
left: 20,
top: 20,
opacity: 1,
background: COLORS[colorNumber],
};
return (
<HotKeys
keyMap={ACTION_KEY_MAP}
handlers={handlers}
>
<textarea
style={style}
className="node"
tabIndex="0"
onKeyDown={this.KeyDown}
></textarea>
</HotKeys>
);
}
}
export default Login;

Related

React time lines

I have a big problem with React TimeLines Package(https://openbase.com/js/react-timelines)
I want something like this photo:
( having 3 P tags with different ClassNames)
but in default case of this package I cant do it!
I think I should use something like createElement and textContent in JS. but I dont know how!
My Codes:
import React, { Component } from "react";
import Timeline from "react-timelines";
import "react-timelines/lib/css/style.css";
import { START_YEAR, NUM_OF_YEARS, NUM_OF_TRACKS } from "./constant";
import { buildTimebar, buildTrack } from "./builder";
import { fill } from "./utils";
const now = new Date("2021-01-01");
const timebar = buildTimebar();
// eslint-disable-next-line no-alert
const clickElement = (element) =>
alert(`Clicked element\n${JSON.stringify(element, null, 2)}`);
class App extends Component {
constructor(props) {
super(props);
const tracksById = fill(NUM_OF_TRACKS).reduce((acc, i) => {
const track = buildTrack(i + 1);
acc[track.id] = track;
return acc;
}, {});
this.state = {
open: false,
zoom: 2,
// eslint-disable-next-line react/no-unused-state
tracksById,
tracks: Object.values(tracksById),
};
}
handleToggleOpen = () => {
this.setState(({ open }) => ({ open: !open }));
};
handleToggleTrackOpen = (track) => {
this.setState((state) => {
const tracksById = {
...state.tracksById,
[track.id]: {
...track,
isOpen: !track.isOpen,
},
};
return {
tracksById,
tracks: Object.values(tracksById),
};
});
};
render() {
const { open, zoom, tracks } = this.state;
const start = new Date(`${START_YEAR}`);
const end = new Date(`${START_YEAR + NUM_OF_YEARS}`);
return (
<div className="app">
<Timeline
scale={{
start,
end,
zoom,
}}
isOpen={open}
toggleOpen={this.handleToggleOpen}
clickElement={clickElement}
timebar={timebar}
tracks={tracks}
now={now}
enableSticky
scrollToNow
/>
</div>
);
}
}
export default App;
builder.js:
export const buildElement = ({ trackId, start, end, i }) => {
const bgColor = nextColor();
const color = colourIsLight(...hexToRgb(bgColor)) ? "#000000" : "#ffffff";
return {
id: `t-${trackId}-el-${i}`,
title: "Bye Title: Hello Type: String",
start,
end,
style: {
backgroundColor: `#${bgColor}`,
color,
borderRadius: "12px",
width: "auto",
height: "120px",
textTransform: "capitalize",
},
};
};

componentDidUpdate(prevProps, prevState, snapshot): prevProps is undefined

I am pretty new to React and I am trying to build this simple web app that takes a stock tag as an input and updates the graph based on the performance of the given stock. However, I can't get my graph to update. I tried using componentDidUpdate(prevProps, prevState, snapshot), but for some reason prevProps is undefined and I don't know/understand why. I tried searching online and reading the doc file, but I still can't figure it out. Any help would be appreciated.
import Search from './Search.js'
import Graph from './Graph.js'
import Sidebar from './Sidebar.js'
import './App.css'
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: [{
x: [],
close: [],
decreasing: { line: { color: '#FF0000' } },
high: [],
increasing: { line: { color: '#7CFC00' } },
line: { color: 'rgba(31,119,180,1)' },
low: [],
open: [],
type: 'candlestick',
xaxis: 'x',
yaxis: 'y'
}]
,
layout: {
width: 1500,
height: 700,
font: { color: '#fff' },
title: { text: 'Stock', xanchor: "left", x: 0 }, paper_bgcolor: '#243b55', plot_bgcolor: '#243b55', yaxis: { showgrid: true, color: '#fff' },
xaxis: {
zeroline: true, color: '#fff', showgrid: true, rangeslider: {
visible: false
}
}
},
searchfield: '',
stocktag: ' '
};
this.onSearchChange = this.onSearchChange.bind(this);
this.onSubmitSearch = this.onSubmitSearch.bind(this);
}
componentDidMount() {
document.body.style.backgroundColor = '#243b55';
this.loadGraphInfo();
}
componentDidUpdate(prevProps, prevState, snapshot){
console.log(prevProps.stocktag);
console.log(prevState.stocktag);
if (prevProps.stocktag !== prevState.stocktag) {
//this.fetchData('SPY');
}
}
onSearchChange = (event) => {
var search = event.target.value;
this.setState({ stocktag: search });
}
onSubmitSearch = (e) => {
var search = this.state.searchfield;
this.setState({ stocktag: search });
}
fetchData(stock) {
//GET DATA
//UPDATE STATE
}
loadGraphInfo() {
if (this.state.stocktag == ' ') {
this.fetchData('SPY');
} else {
this.fetchData(this.state.stocktag);
}
}
render() {
return (
<div className="App" >
<Sidebar />
<Search searchChange={this.onSearchChange} submitChange={this.onSubmitSearch} />
<Graph data={this.state.data} layout={this.state.layout} />
</div>
);
}
}
export default App;
import React, { Component } from 'react';
import './Search.css'
const Search = ({ searchChange, submitChange }) => {
return (
<div>
<div class="SearchCompInput">
<input class="SearchBar" type="text" onChange={searchChange}/>
</div>
<div class="SearchCompButton">
<button class="SearchButton" onClick={submitChange}>Search</button>
</div>
</div>
);
}
export default Search;
The prevProps.stocktag is undefined because you didn't pass any props to App component. Try this in your index.js you will see preProps value but actually it does not make any sense.
render(<App stocktag='' />, document.getElementById('root'));
componentDidUpdate(prevProps, prevState, snapshot){
console.log(prevProps.stocktag);
console.log(prevState.stocktag);
if (prevProps.stocktag !== prevState.stocktag) {
//this.fetchData('SPY');
}
}
I am not quite sure on what you are trying to accomplish here but the first thing I notice is you setState of stocktag to this.state.searchfield which is ' ' in your onSubmitSearch function.
onSearchChange = (event) => {
var search = event.target.value;
this.setState({ stocktag: search });
}
onSubmitSearch = (e) => {
var search = this.state.searchfield;
this.setState({ stocktag: search });
}
Add I will also like to add that it is good practice to set value of input to a state value like so
import React, { Component, useState } from 'react';
import './Search.css'
const Search = ({ searchChange, submitChange }) => {
const [inputValue, setInputValue] = useState('')
const handleChange = (e) => {
setInputValue(e.target.value)
searchChange(e)
}
return (
<div>
<div class="SearchCompInput">
<input class="SearchBar" type="text" value = {inputValue} onChange={handleChange}/>
</div>
<div class="SearchCompButton">
<button class="SearchButton" onClick={submitChange}>Search</button>
</div>
</div>
);
}
export default Search;
I had this problem, and it was because there was a child class that was calling super.componentDidUpdate() WITHOUT passing in the parameters. So the child class looked something like:
componentDidUpdate() {
super.componentDidUpdate();
... <-- other stuff
}
And I had to change it to:
componentDidUpdate(prevProps, prevState) {
super.componentDidUpdate(prevProps, prevState);
... <-- other stuff
}

Redux store isn't getting updated

I have built this app using create-react-native-app, the action is dispatched but the state isn't being updated and I'm not sure why.
I see the action being logged (using middleware logger) but the store isn't getting updated, I am working on Add_Deck only for now
Here is my reducer:
// import
import { ADD_CARD, ADD_DECK } from './actions'
// reducer
export default function decks(state ={}, action){
switch(action.type){
case ADD_DECK:
return {
...state,
[action.newDeck.id]: action.newDeck
}
case ADD_CARD:
return {
...state,
[action.deckID]: {
...state[action.deckID],
cards: state[action.deckID].cards.concat([action.newCard])
}
}
default: return state
}
}
Actions file:
// action types
const ADD_DECK = "ADD_DECK";
const ADD_CARD = "ADD_CARD";
// generate ID function
function generateID() {
return (
"_" +
Math.random()
.toString(36)
.substr(2, 9)
);
}
// action creators
function addDeck(newDeck) {
return {
type: ADD_DECK,
newDeck
};
}
// export
export function handleAddDeck(title) {
return dispatch => {
const deckID = generateID();
// const newDeck = { id: deckID, title, cards: [] };
dispatch(addDeck({ id: deckID, title, cards: [] }));
};
}
function addCard(deckID, newCard) {
// { question, answer }, deckID
return {
type: ADD_CARD,
deckID,
newCard
};
}
// export
export function handleAddCard(deckID, content) {
// { question, answer }, deckID
return dispatch => {
const newCard = { [generateID()]: content };
dispatch(addCard(deckID, newCard));
};
}
And react-native component:
import React, { Component } from 'react';
import { View, Text, StyleSheet, TextInput, TouchableOpacity } from "react-native";
import {red, white} from '../utils/colors'
import { connect } from 'react-redux'
import { handleAddDeck } from '../redux/actions'
class AddDeck extends Component {
state = {
text:""
}
handleSubmit = () => {
this.props.dispatch(handleAddDeck(this.state.text))
this.setState(()=>{
return { text: ""}
})
}
render() {
return (
<View style={styles.adddeck}>
<Text> This is add deck</Text>
<TextInput
label="Title"
style={{ height: 40, borderColor: "gray", borderWidth: 1 }}
onChangeText={text => this.setState({ text })}
placeholder="Deck Title"
value={this.state.text}
/>
<TouchableOpacity style={styles.submitButton} onPress={this.handleSubmit}>
<Text style={styles.submitButtonText}>Create Deck</Text>
</TouchableOpacity>
</View>
);
}
}
function mapStateToProps(decks){
console.log("state . decks", decks)
return {
decks
}
}
export default connect(mapStateToProps)(AddDeck);
const styles = StyleSheet.create({
adddeck: {
marginTop: 50,
flex: 1
},
submitButton: {
backgroundColor: red,
padding: 10,
margin: 15,
height: 40,
},
submitButtonText: {
color: white
}
});
I guess you forgot to export your types from the actions file thus the switch(action.type) does not trigger the needed case statement.
Maybe try to add as the following:
export const ADD_DECK = "ADD_DECK";
export const ADD_CARD = "ADD_CARD";
Or further debugging just to see if the values are the ones what you are looking for:
export default function decks(state = {}, action) {
console.log({type:action.type, ADD_DECK}); // see what values the app has
// further code ...
}
I hope that helps! If not, let me know so we can troubleshoot further.

React - Why is componentDidMount event called instantly

I've playing around with animation implemented with reactjs.
In the app I created a car which drives around a track. On this track there are obstacles, which the car should recognize.
I'm using window.setInterval for the repeating events. Maybe this is not the best option, but actually I don't know how to do else.
Since some changes, there are multiple intervals running.
But actually I don't know the reason for it. Can anybody give me a hint, why the racer component is instantly running in componentdidmount event?
The Racer component is giving the current position and degree / ankle to the Track component. The Track component is storing these values in states and giving it to the Racer component as props. But this should not lead to instantly firing componentdidmount event of Racer component, or?
Here is my code:
App.js
import React, { Component } from 'react';
import Track from './components/track.js';
const uuidv1 = require('uuid/v1');
class App extends Component {
constructor(props) {
super(props);
this.state = {
obstacles: [
{
key: uuidv1(),
position: {
left: 500,
top:10,
},
width: 25,
height: 25,
},
{
key: uuidv1(),
position: {
left: 650,
top:60,
},
width: 25,
height: 25,
}
],
};
}
render() {
return (
<div className="App">
<Track width={800} height={100} obstacles={this.state.obstacles}>
</Track>
</div>
);
}
}
export default App;
Track.js
import React, { Component } from 'react';
import styled from 'styled-components';
import Racer from './racer.js';
import Obstacle from './obstacle';
import centralStrip from '../images/centralStrip.png';
const uuidv1 = require('uuid/v1');
class Track extends Component {
constructor(props) {
super(props);
this.state = {
racerCurrentPosition: {
top: 60,
left:150
},
racerDegree: 0,
};
}
componentDidMount() {
}
handleObstacleCheck(position, racerPosition) {
let obstacleFound = false;
obstacleFound = this.props.obstacles.map((obstacle) => {
let returnValue = false;
let obstacleRect = document.getElementById(obstacle.key).getBoundingClientRect();
if( position.right >= obstacleRect.left && position.right <= obstacleRect.right && racerPosition.top >= obstacleRect.top && racerPosition.bottom <= obstacleRect.bottom) {
returnValue = true;
}
return returnValue;
});
let isObstacleFound = false;
if(obstacleFound.indexOf(true) !== -1) {
isObstacleFound = true;
}
return isObstacleFound;
}
handleRacerPositionChange(position) {
this.setState({
racerCurrentPosition: position,
});
}
handleRacerDegreeChange(newDegree) {
this.setState({
racerDegree: newDegree,
});
}
render() {
return (
<TrackImage key={uuidv1()}
id="track"
width={this.props.width}
height={this.props.height}>
<Racer key={uuidv1()}
position={this.state.racerCurrentPosition}
onRacerPositionChange={this.handleRacerPositionChange.bind(this)}
degree={this.state.racerDegree}
onRacerDegreeChange={this.handleRacerDegreeChange.bind(this)}
obstacleFound={this.state.obstacleFound}
trackWidth={this.props.width}
trackHeight={this.props.height}
onObstacleCheck={this.handleObstacleCheck.bind(this)}
/>
{
this.props.obstacles.map((obstacle) => {
return (
<Obstacle key={obstacle.key}
id={obstacle.key}
position={obstacle.position}
width={obstacle.width}
height={obstacle.height}
/>
);
})
}
</TrackImage>
);
}
}
export default Track;
Racer.js
import React, { Component, Fragment } from 'react';
import styled from 'styled-components';
import HelperDistance from './helpers/distance.js';
import HelperCenterCar from './helpers/centerCar.js';
import racerImage from '../images/racer.png';
const uuidv1 = require('uuid/v1');
class Racer extends Component {
constructor(props) {
super(props);
this.state = {
key: uuidv1(),
intervalId: 0,
speed: 0,
helperForLeftPositioning: 0,
helperForTopPositioning: 0,
isMoving: false,
collision: false,
centerOfCarCoordinates: {
x: 25,
y: 12.5
},
obstacleFound: false,
};
this.start = this.start.bind(this);
this.move = this.move.bind(this);
}
componentDidMount() {
if(this.state.intervalId === 0) {
this.start();
}
}
componentWillUnmount() {
window.clearInterval(this.state.intervalId);
}
start() {
this.setState({
speed: 3,
isMoving: true,
}, () => {
this.createInterval();
});
}
stop() {
this.setState({
speed: 0,
isMoving: false,
}, () => {
window.clearInterval(this.state.intervalId);
});
}
move() {
if(this.state.obstacleFound === true) {
let newDegree;
if(this.props.degree === 0) {
newDegree = 360;
}
newDegree--;
this.props.onRacerDegreeChange(newDegree);
}
this.step();
}
step() {
if(this.state.isMoving) {
//...calculate new position
this.setState({
helperForTopPositioning: helperForTopPositioning,
helperForLeftPositioning: helperForLeftPositioning,
},() => {
let position = {
left: positionNewLeft,
top: positionNewTop
};
this.props.onRacerPositionChange(position);
});
}
}
createInterval = () => {
let intervalId = window.setInterval(() => {
this.move();
console.log("IntervalId: " + intervalId);
},100);
this.setState({
intervalId: intervalId,
})
}
handleDistanceChange(position) {
let racerRect = document.getElementById(this.state.key).getBoundingClientRect();
let obstacleFound = this.props.onObstacleCheck(position, racerRect);
if(this.state.obstacleFound !== obstacleFound) {
this.setState({
obstacleFound: obstacleFound
});
}
}
render() {
return (
<Fragment>
<Car key={this.state.key} id={this.state.key} position={this.props.position} degree={this.props.degree}>
<HelperCenterCar key={uuidv1()} position={this.state.centerOfCarCoordinates} degree={this.props.degree} />
<HelperDistance key={uuidv1()} onChange={this.handleDistanceChange.bind(this)} position={this.state.centerOfCarCoordinates} degree={this.props.degree} />
</Car>
</Fragment>
);
}
}
export default Racer;
The HelperCenterCar and HelperDistance are components, which helps to identify, if there is an obstacle in the way. I'll post just the code of HelperDistance, because here instantly state updates are fired.
HelperDistance.js
import React, { Component } from 'react';
import styled from 'styled-components';
const uuidv1 = require('uuid/v1');
class HelperDistance extends Component {
constructor(props) {
super(props);
this.state = {
key: uuidv1(),
};
}
componentDidMount() {
this.handleOnChange();
}
componentDidUpdate(prevProps, prevState, snapshot) {
this.handleOnChange();
}
handleOnChange() {
let position = document.getElementById(this.state.key).getBoundingClientRect();
this.props.onChange(position);
}
render() {
return (
<Line id={this.state.key} key={this.state.key} position={this.props.position} degree={this.props.degree} />
);
}
}
export default HelperDistance;

React-dnd not working in Cordova on iOS

I'm using the react-dnd-touch-backend.
I'm able to get my DragSources to drag correctly, but the DropTargets don't accept them (or react to being dragged over).
The application only uses one wrapper component for each role (DragSource and DropTarget). I have also defined a custom drag layer. The drag/drop worked fine before adding the custom drag layer except my DragSources were invisible on iOS (which is why I added the drag layer in the first place), but now I can see the DragSources, but the DropTargets don't work.
Any help is much appreciated.
DragSource:
import React from "react";
import cn from "util/cn";
import {isCordova} from "util/detect-platform";
import {DragSource} from "react-dnd";
import {getEmptyImage} from "react-dnd-html5-backend";
require("./style.scss");
const TYPE = "DRAG-CONTAINER";
const source = {
beginDrag({value, left, top, children, DragPreviewComponent}) {
return {value, left, top, children, DragPreviewComponent};
}
};
function collect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
connectDragPreview: connect.dragPreview(),
isDragging: monitor.isDragging()
};
}
function getStyles(props) {
const {left, top, isDragging} = props;
const transform = `translate3d(${left}px, ${top}px, 0)`;
return {
transform: transform,
WebkitTransform: transform,
opacity: isDragging ? 0 : 1
};
}
#DragSource(TYPE, source, collect)
export default class DragContainer extends React.Component {
static propTypes = {
value: React.PropTypes.any
};
static defaultProps = {style: {}};
componentDidMount() {
if(!isCordova()) {
this.props.connectDragPreview(getEmptyImage(), {
captureDraggingState: true
});
}
}
render() {
const {className, isDragging, connectDragSource, style} = this.props;
const classNames = cn(
"Drag-container",
isDragging ? "Drag-container--dragging" : null,
className
);
return connectDragSource(
<div {...this.props} className={classNames} value={null} style={{...style, ...getStyles(this.props)}}/>
);
}
}
DropTarget:
import React from "react";
import {DropTarget} from "react-dnd";
import cn from "util/cn";
require("./style.scss");
const TYPE = "DRAG-CONTAINER";
const target = {
drop(props, monitor) {
const {onDrop} = props;
const {value} = (monitor.getItem() || {value: null});
if(typeof onDrop === "function") {
setTimeout(() => onDrop(value), 100);
}
}
};
function collect(connect, monitor) {
return {
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver()
};
}
#DropTarget(TYPE, target, collect)
export default class DropContainer extends React.Component {
static propTypes = {
onDrop: React.PropTypes.func
};
render() {
const {connectDropTarget, isOver, className} = this.props;
const classNames = cn("Drop-container", isOver ? "Drop-container--over" : null, className);
return connectDropTarget(
<div {...this.props} className={classNames} onDrop={null} onDragEnter={null} onDragExit={null}/>
);
}
}
Custom Drag Layer:
import React from "react";
import {DragLayer} from "react-dnd";
const layerStyles = {
position: "fixed",
pointerEvents: "none",
width: "100%",
height: "100%",
zIndex: 100,
left: 0,
top: 0
};
function getItemStyles(props) {
const { initialOffset, currentOffset } = props;
if (!initialOffset || !currentOffset) {
return {
display: 'none'
};
}
let { x, y } = currentOffset;
if (props.snapToGrid) {
x -= initialOffset.x;
y -= initialOffset.y;
[x, y] = snapToGrid(x, y);
x += initialOffset.x;
y += initialOffset.y;
}
const transform = `translate(${x}px, ${y}px)`;
return {
transform: transform,
WebkitTransform: transform
};
}
#DragLayer(monitor => ({
item: monitor.getItem(),
itemType: monitor.getItemType(),
initialOffset: monitor.getInitialSourceClientOffset(),
currentOffset: monitor.getSourceClientOffset(),
isDragging: monitor.isDragging()
}))
export default class CustomDragLayer extends React.Component {
render() {
const {item, itemType, isDragging} = this.props;
if (!isDragging || !item) return null;
const {DragPreviewComponent} = item;
if(!DragPreviewComponent) return null;
return (
<div style={layerStyles}>
<div style={getItemStyles(this.props)}>
<DragPreviewComponent {...item}/>
</div>
</div>
);
}
}
The problem was this issue in the react-dnd-touch-backend library:
https://github.com/yahoo/react-dnd-touch-backend/issues/34
Rolling back to version 0.2.7 fixed the issue.

Categories

Resources