How to pass an onKeyDown event as a prop to parent component? - javascript

I have an input with an onChange attribute and an onKeyDown attribute. The onChange attribute receives a value of {(e) => props.change(e)} and in the parent component I assign the change prop to a handleChange function. I want to do the same thing with my onKeyDown attribute, however I face two issues:
When I use {(e) => props.key(e)}, Chrome Devtools says that key is not a prop. When I try passing {key} instead of (props) to the child component, Chrome Devtools says that key is not a function.
I'm trying to pass the prop so that I can consume the key code value in the parent component and execute some logic.
I've also tested to make sure the function is working within Home.js. If someone could give a solution and an explanation as to why this happens I would be appreciative.
Here is an example of my code:
/ App.js
export default function App() {
const key = (e) => {
if (e.keyCode === 8) {
...
}
}
const change = (e) => {
return ...
}
return
<Home
key={key}
change={change}
/>
}
/ Home.js
export default function Home(props) {
return
<input
onChange={(e) => props.change(e)}
onKeyDown={(e) => props.key(e)}
/>
}

key is a special prop in React and gets special treatment:
[…] there are two special props (ref and key) which are used by React, and are thus not forwarded to the component.
So it should work if you change the name of the prop:
App.js
export default function App() {
// …
return
<Home
myKey={key}
change={change}
/>
}
Home.js
export default function Home(props) {
return
<input
onChange={(e) => props.change(e)}
onKeyDown={(e) => props.myKey(e)}
/>
}

Related

How to pass two parameters to custom event handler in React?

I am using Ant design and they have a component called Switch, Switch have a custom event handler
import "./styles.css";
import "antd/dist/antd.css";
import { Switch } from "antd";
import { useState } from "react";
export default function App() {
const [status, setStatus] = useState(true);
const handleChange = (e) => {
// e is a boolean variable, true or false
console.log(e);
setStatus(e);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<Switch checked={status} onChange={handleChange}></Switch>
</div>
);
}
and I have so much of question about that kind of syntax
Does
onChange={handleChange}
is equivalent with
onChange={(e) => handleChange(e)}
If for some reason, I can only write
onChange={handleChange}
how can I pass the real event handler to handleChange to do some stopPropagation, some thing likes
const handleChange = (e, reale) => {
reale.stopPropagation()
setStatus(e);
};
Simple codesandbox to understand what I said.
Does
onChange={handleChange}
is equivalent with
onChange={(e) => handleChange(e)}
They're equivalent if and only if the function receives one argument. But for ant design switches, the onChange actually passes in two parameters: the new value, and the event object. So if you want to create a new function and then call handleChange in that function, you'll probably want to pass both parameters through:
onChange={(value, e) => handleChange(value, e)}
You can write thing something like
onChange={(e) => handleChange(e, reale)}

Connect Material-ui ToggleButtonGroup to redux-form

I'm trying to connect material-ui ToggleButtonGroup with redux form and getting issues with this.
Here is my code:
<Field
name='operator'
component={FormToggleButtonGroup}
>
<ToggleButton value='equals'>Equal</ToggleButton>
<ToggleButton value='not_equals'>Not equal</ToggleButton>
</Field>
.. and my component, passed to Field:
const FormToggleButtonGroup = (props) => {
const {
input,
meta,
children
} = props;
return (
<ToggleButtonGroup
{...input}
touched={meta.touched.toString()}
>
{children}
</ToggleButtonGroup>
);
};
export default FormToggleButtonGroup;
the problem is, when I select value (toggle option), selected value is not passed to redux store, it passed only after loosing focus and then throws error 'newValue.splice is not a function'
Please help to deal with this issue
Sandbox with sample code
Playing with the component I finally found the solution.
I need manually assign new value got from ToggleButtonGroup component and put this value to redux store. Here is how working code looks:
const FormToggleButtonGroup = (props) => {
const {
input,
meta,
children,
...custom
} = props;
const { value, onChange } = input;
return (
<ToggleButtonGroup
{...custom}
value={value}
onChange={(_, newValue) => {
onChange(newValue);
}}
touched={meta.touched.toString()}
>
{children}
</ToggleButtonGroup>
);
};
Main change is getting redux's function onChange and call it with new value, selected when value toggled. There is onChange related to ToggleButtonGroup component and another onChange related to Redux. You need to call latter when ToggleButtonGroup's onChange occurs.

React - functional component does not return updated variable values

I have a class Component FooPage which renders an imported functional Component BarForm. I pass handleSubmit as a prop to BarForm and want to capture the inputData value. The issue is the value is returned as the initial value.
To help debugging: before I submit, the latest value of inputData was logged correctly, and the submit did not trigger re-rendering. Still, FooPage console logs "initial value". What's more, changing onSubmit callback from handleSubmit(inputData) to arrow function (event) => handleSubmit(inputData)(event) fixes the problem.
While I know I can achieve this by useState, I want to understand why the updated inputData is returned as initial value even without re-rendering, and why using arrow function as callback fixed the problem.
const BarForm = ({ handleSubmit }) => {
let inputData = "initial value"
console.log("I just re-rendered.") //Check BarForm did not re-render when submit.
return (
<form onSubmit={ handleSubmit(inputData) }> {/* won't work, but arrow function does */}
<input
onChange = {(event) => {
inputData = event.target.value; //update inputData
console.log(inputData); //confirm the value of inputData before submit
}}
/>
<button type="submit">Submit</button> {/* But */}
</form>
)
}
class FooPage extends React.Component {
handleSubmit = (inputData) => (event) => {
event.preventDefault(); //Don't re-render
console.log(inputData); //See the output
}
render() {
return (
<BarForm handleSubmit = {this.handleSubmit} />
)
}
}
ReactDOM.render(<FooPage />, document.getElementById("app"));
<script src="https://unpkg.com/react#16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js" crossorigin></script>
<div id="app"></div>
When you set <form onSubmit={ handleSubmit(inputData) }>, what you are actually doing in this case is calling the handleSubmit from FooPage function which returns a new function with inputData as captured when the component was first rendered as part of the function's scope.
When you call it with the arrow function, you don't actually create a new function when the component renders. You create the function onSubmit.

ReactJS: lifting the parameter several levels up?

I want to upstream the key of the component on change. I.e., I write
onChange= {(e) => this.props.onChange(e, key)}
However, in my case this.props.onChange also points in its turn to its props.onChange function. I've tried to define all the hierarchically "upper" assignments as onChange={this.props.onChange} as well as onChange={(e,key) => this.props.onChange(e,key)}, but nothing helps the fact that key is undefined when it comes to the actual function body.
Here's the full code of that what has to do with the peoblem:
handleValueChange = (e, key) => {
console.log('Event was on ' + key);
let currElemData = this.state.currentElementsData.slice();
currElemData[key] = {value: e.target.value};
this.setState({currentElementsData: currElemData});
};
addFilter = () => {
let activeFiltersNow = this.state.activeFilterElements.slice();
activeFiltersNow.push(<Filter key={this.state.filterCounter} onSelect={(e, key) => this.handleReferenceSelection(e, key)}
onChange={(e,key) =>this.handleValueChange(e, key)}/>);
let currElemData = this.state.currentElementsData.slice();
currElemData.push(InitialHelper.getInitialFilterData());
this.setState({activeFilterElements: activeFiltersNow, currentElementsData: currElemData, filterCounter: this.state.filterCounter++});
};
...
class Filter extends Component {
render() {
return <div className="filterContainer">
{this.props.isFirst? '':<FilterPrefix />}
<FilterReference onSelect={(e,key) => this.props.onSelect(e,key)} key={this.props.key}/>
<FilterAssignment />
<FilterValue onChange={(e,key) => this.props.onChange(e,key)} key={this.props.key}/>
<DeleteFilterButton />
</div>
}
}
...
class FilterValue extends Component{
render() {
return <input onChange={(e) => this.props.onChange(e,this.props.key)} key={this.props.key}/>
}
loadSuggestions(reference) {
}
}
I'm not quite sure what you are trying to do here, but I've noticed that you are falling for a pretty common ReactJs pitfall which is that:
Keys serve as a hint to React but they don't get passed to your
components. If you need the same value in your component, pass it
explicitly as a prop with a different name
meaning that this.props.key will always be undefined. So, I'm afraid that all the instances in where you are using this.props.key are not going to behave as you expect...

Stateless React component with onChange handler: Synthetic event warning

I am trying do do a simple implementation on a stateful component who's state is managed by a stateless Child. Currently the handler only triggers a console.log.
Expected behavior:
When an field is updated the parent component should trigger a console.log.
Actual behavior
The setInterest is never triggered and instead I'm getting an error about synthetic events:
This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property `nativeEvent` on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist().
The components render visually as expected, and I get no other errors either in the browser of Webpack.
Any help would be greatly appreciated.
Stateful component:
// Setting the parameters of the market
export class Parameters extends React.Component {
// Constructor setting default state
constructor ( props ) {
super ( props )
// Set the state objects
this.state = {
interest: {
pessimistic: this.props.pessimistic || 1,
historical: this.props.historical || 4,
optimistic: this.props.optimistic || 7
}
}
// Bind the functions for use in the render
this.setInterest = this.setState.bind( this )
}
// Set the parameters
setInterest( e ) {
console.log('I AM NEVER TRIGGERED')
}
// Rendering of message
render( ) {
return(
<div>
<ParametersView
handleChange={ this.setInterest }
interest={ this.state.interest } />
<DesiresView />
</div>
)
}
}
Stateless component
// Import react
import React from 'react'
export const ParametersView = ( { handleChange, interest } ) => {
return (
<div>
<span id="assumptions">
<input
onChange={ handleChange }
value={interest.pessimistic}
id="pessimistic" type="number" name="pessimistic" />
<input
onChange={ handleChange }
value={interest.historical}
id="historical" type="number" name="historical" />
<input
onChange={ handleChange }
value={interest.optimistic}
id="optimistic" type="number" name="optimistic" />
</span>
</div>
)
}
export const DesiresView = ( ) => {
return ( <p>No desire view yet</p> )
}
You have a typo.
this.setInterest = this.setState.bind( this ) needs to be
this.setInterest = this.setInterest.bind( this )

Categories