There is an input field and another component. I need to get the event keyCode to the second component.
I don't get both components connected as some posts said ref is not the best attempt for this. I don't really understand that...
Parent
class Parent extends Component {
render () {
return(
<Input onKeyDown={() => { console.log('triggered keydown') }} />
<Child />
)
}
}
Child
class Child extends Component {
handleKeyDown (e) {
console.log(e.keyCode) // <- Get Keycode from parent triggered keydown event
}
render () {
}
}
Use setState() to update the current keyCode in state, and pass it to the child via prop.
In the child you can use the prop directly or process it in componentWillReceiveProps(), and set the result to the state.
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
onKeyDown = (e) => this.setState({ keyCode: e.keyCode });
render() {
const { keyCode } = this.state;
return (
<div>
<input onKeyDown={this.onKeyDown} />
<Child keyCode={keyCode} />
</div>
);
}
}
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
doubleKeyCode: []
};
}
handleKeyDown = (keyCode = 0) => this.setState((prevState) => ({
doubleKeyCode: [...prevState.doubleKeyCode, keyCode * 2]
}));
componentWillReceiveProps(nextProps) {
this.handleKeyDown(nextProps.keyCode);
}
render () {
const { doubleKeyCode } = this.state;
console.log(`render: ${doubleKeyCode}`);
return (
<div>{doubleKeyCode.join(', ')}</div>
);
}
}
ReactDOM.render(
<Parent />,
demo
);
<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="demo"></div>
Related
This may seem kind of basic but I'm just learning how to use React. Currently what I have going is when I type in the input field and submit, the system console logs my 'search' input. What I'm trying to do is pass my 'search' data from my child component to the parent. Looking for any tips or leads to the right direction.
This is what I have for my child component:
export default class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
search: ''
};
}
onChange = event => {
this.setState({ search: event.target.value });
};
onSubmit = event => {
const { search } = this.state;
event.preventDefault();
console.log(search);
};
render() {
return (
<div className='search-bar'>
<form onSubmit={this.onSubmit}>
<input
className='search'
type='text'
placeholder='Search'
onChange={this.onChange}
search={this.props.search}
value={this.state.searchinput}
parentCallback={this.onChange}
></input>
</form>
<FontAwesomeIcon className='search-icon' icon={faSearch} />
</div>
);
}
}
And in my Parent component (nothing much at the moment)
export default class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
search: ''
};
}
searchUpdate = search => {
console.log(search);
};
render() {
console.log(this.props.search);
return (
<div className='container'>
<SearchBar/>
</div>
);
}
}
Generally to pass data from child component to Parent Component, you can pass a reference of a function as props to child component from parent component and call that passed function from child component with data.
You can do something like this:
export default class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
search: ''
};
}
onChange = event => {
this.setState({ search: event.target.value });
};
onSubmit = event => {
const { search } = this.state;
event.preventDefault();
console.log(search);
this.props.passSearchData(search);
};
render() {
return (
<div className='search-bar'>
<form onSubmit={this.onSubmit}>
<input
className='search'
type='text'
placeholder='Search'
onChange={this.onChange}
search={this.props.search}
value={this.state.searchinput}
parentCallback={this.onChange}
></input>
</form>
<FontAwesomeIcon className='search-icon' icon={faSearch} />
</div>
);
}
In parent component:
export default class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
search: ''
};
}
searchUpdate = search => {
console.log(search);
this.setState({ ...state, search: search })
};
render() {
console.log(this.props.search);
return (
<div className='container'>
<SearchBar passSearchData={this.searchUpdate} />
</div>
);
}
The simplest way would be to pass a function from parent to child:
// in parent component
const setSearchValue = (search) => {
// setState to search
this.setState({search});
}
render (){
return <>
<SearchBar onsearch={this.setSearchValue} />
</>
}
// in child component
// change your searchUpdate
searchUpdate = () => {
const {onsearch} = this.state;
// function call to pass data to parent
this.props.onsearch(onsearch)
}
Just have a function that is passed as a prop to the child component. Let child component do the handle change part and pass the value back to the parent and then do whatever you want to with the value
Code sandbox: https://codesandbox.io/s/react-basic-example-vj3vl
Parent
import React from "react";
import Search from "./Search";
export default class Parent extends React.Component {
searchUpdate = search => {
console.log("in parent", search);
};
render() {
console.log(this.props.search);
return (
<div className="container">
<Search handleSearch={this.searchUpdate} />
</div>
);
}
}
Child
import React from "react";
export default class Search extends React.Component {
constructor(props) {
super(props);
this.state = {
search: ""
};
}
onChange = event => {
this.setState({ search: event.target.value }, () => {
console.log("in child", this.state.search);
this.props.handleSearch(this.state.search);
});
};
onSubmit = event => {
const { search } = this.state;
event.preventDefault();
console.log(search);
};
render() {
return (
<div className="search-bar">
<form onSubmit={this.onSubmit}>
<input
className="search"
type="text"
placeholder="Search"
onChange={this.onChange}
search={this.props.search}
value={this.state.searchinput}
/>
</form>
</div>
);
}
}
I have two components (Parent component & Child component) in my react app. I have two button clicks in my child component and I need to pass two props to the parent component. I use the code as follows.
The problem is, I can't include both methods in the parent component's element, but I need to. How can I use both edituser and deleteuser functions in the parent component?
Child component:
class EnhancedTable extends React.Component {
constructor(props){
super(props);
this.state = {
userID: 10
};
this.editByUserId = this.sendUserId.bind(this);
this.DeleteByUserId = this.sendUserId.bind(this);
}
editByUserId() {
this.props.onClick(this.state.userID);
}
DeleteByUserId() {
this.props.onClick(this.state.userID);
}
render() {
return (
<button onClick={this.sendUserId}>
<BorderColorIcon onClick={this.editUserById} className="action margin-r" />
<DeleteIcon onClick={this.deleteUserById} className="action margin-r" />
</button>
)
}
}
Parent component:
Import EnhancedTable from './EnhancedTable';
class Users extends Component {
constructor(props) {
super(props);
this.state = {
userID: null
};
this.editUser = this.editUser.bind(this);
this.deleteUser = this.deleteUser.bind(this);
}
editUser(idd) {
this.setState({
userID : idd
})
console.log("User Edited");
}
deleteUser(idd) {
this.setState({
userID : idd
})
console.log("User Deleted");
}
render() {
return(
<EnhancedTable onClick = {(e)=>{this.editUser; this.deleteUser;}}/>
)
}
}
You missed your ()
<EnhancedTable onClick = {(e)=>{this.editUser(); this.deleteUser();}}/>
You are doing it right in
<EnhancedTable onClick = {(e)=>{this.editUser; this.deleteUser;}}/>
A minor change is needed:
<EnhancedTable onClick = {(e)=>{this.editUser(e); this.deleteUser(e);}}/>
A quick reference for what changed here:
let x = () => {
console.log('hello');
}
x; // This simply does nothing as it is just a reference to the function
x(); // This instead invokes the function
I am learning the concept of States in React. I am trying to understand the difference between using this.handleChange, and this.state.handleChange.
I would be grateful if someone could explain to me, the exact difference between the two, and why would this.state.handleChange not work?
class MyApp extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: ''
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
inputValue: event.target.value
});
}
render() {
return (
<div>
< GetInput input={this.state.inputValue} handleChange={this.handleChange} />
{ /* this.handleChanges, and this.state.handleChanges */ }
< RenderInput input={this.state.inputValue} />
</div>
);
}
};
class GetInput extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>Get Input:</h3>
<input
value={this.props.input}
onChange={this.props.handleChange}/>
</div>
);
}
};
class RenderInput extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h3>Input Render:</h3>
<p>{this.props.input}</p>
</div>
);
}
};
You can technically call this.state.handleChange so long as you add handleChange in your state.
But it doesn't really make sense since you don't want React to keep a track of it, and it will probably not change (unless you are doing some clever tricks).
constructor(props) {
super(props);
this.state = {
handleChange: e => {
e.preventDefault();
console.log("this.state.handleChange");
}
};
}
One would normally declare a member function in a class.
handleChange = e => {
e.preventDefault();
console.log("this.handleChange");
};
Here is the full working code
(working demo available on CodeSandBox).
import React from "react";
import ReactDOM from "react-dom";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
handleChange: e => {
e.preventDefault();
console.log("this.state.handleChange");
}
};
}
handleChange = e => {
e.preventDefault();
console.log("this.handleChange");
};
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<button onClick={this.handleChange}>this.handleChange</button>
<button onClick={this.state.handleChange}>
this.state.handleChange
</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
When you say this.state.something this means something is in the state field of the class. When you say this.someFunction this means something is in the class itself. this here is pointing out our class.
class App extends React.Component {
state = {
something: "Something",
}
someFunction = () => console.log(this.state.something);
render() {
return (
<div>
<button onClick={this.someFunction}>Click</button>
</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>
So, you can't use this.state.handleChange since there is no handleChange in the state. It is a function belongs to the class. This is why we use this.handleChange.
you can store a function in state
constructor(super){
super(props)
this.state = {
generateANumber: () => this.setState({ number: Math.floor(Math.random() * 100) }),
number: 0
}
}
then if you want to call it in your render method
render() {
return <p> {this.state.number} <button onClick={() => this.state.generateANumber()} Press Me To Generate A New Number </button> </p>
}
This is the concept of storing a function in state. This.function just means the function belongs to that class so you can use it using the this keyword.
I am attempting to return a component based on a parameter that was passed on a onClick handler this.showComponentToRender('features'). If features is clicked, it runs the showComponentToRender(name) and sets the state and in the render(), the {this.state.showComponent} shows the proper component.
However, a problem surfaces when I attempt to pass a prop resetFeatures={this.props.resetFeatures} within the
showFeatures() {
return (<FeaturesList
updateCad={this.props.updateCad}
resetFeatures={this.props.resetFeatures}
/>);
}
Clicking on the RESET A4 link, calls the resetCrossbow() which activates a function in the parent component. The parent component updates its state, and passes the state as a prop to its child.
For some reason, I can not get the resetFeatures prop to come into the <FeaturesList /> component if I return it within a function that gets set in state. Why is this? I am looking for suggestions to fix.
If I do the traditional method of placing the <FeaturesList /> within the return of the render(), all is well.
Here's the component
import React, { Component } from 'react';
import FeaturesList from './FeaturesList';
import ColorsList from './ColorsList';
import './../assets/css/features-menu.css';
export default class FeaturesMenu extends Component {
constructor(props) {
super(props);
this.state = {
showComponent: this.showFeatures()
};
this.showFeatures = this.showFeatures.bind(this);
this.showColors = this.showColors.bind(this);
}
showFeatures() {
return (<FeaturesList
updateCad={this.props.updateCad}
resetFeatures={this.props.resetFeatures}
/>);
}
showColors() {
this.props.resetCrossbow();
return <ColorsList switchColor={this.props.switchColor} />
}
showComponentToRender(name) {
if (name === 'features') {
this.setState({
showComponent: this.showFeatures()
});
} else {
this.setState({
showComponent: this.showColors()
})
}
}
render() {
// console.log(`this.props.resetFeatures: ${this.props.resetFeatures}`);
return (
<div id="features-menu-wrapper">
<nav id="features-menu">
<li onClick={() => this.showComponentToRender('features')}>FEATURES</li>
<li onClick={() => this.showComponentToRender('colors')}>COLORS</li>
<li onClick={() => this.props.resetCrossbow()}>RESET A4</li>
</nav>
<div id="component-wrapper">
{this.state.showComponent} // <- I am not able to pass resetFeatures prop if I do it this way. Why?
{/* <FeaturesList
updateCad={this.props.updateCad}
resetFeatures={this.props.resetFeatures} <- I am able to pass resetFeatures prop as normal.
/>
<ColorsList switchColor={this.props.switchColor} /> */}
</div>
</div>
);
}
}
The easiest way to achieve results is pass additional properties to render specific components function and use spread to pass these props to the rendered component:
const FeaturesList = ({additional = 'Empty'} = {}) => <div>Feature List with additional prop <b>{additional}</b></div>
const ColorsList = ({additional = 'Empty'} = {}) => <div>Colors List with additional prop <b>{additional}</b></div>
class FeaturesMenu extends React.Component {
constructor(props) {
super(props);
this.state = {
showComponent: this.showFeatures({additional: 'Initial features'})
};
this.showFeatures = this.showFeatures.bind(this);
this.showColors = this.showColors.bind(this);
}
showFeatures(props) {
return (<FeaturesList
updateCad={this.props.updateCad}
resetFeatures={this.props.resetFeatures}
{...props}
/>);
}
showColors(props) {
this.props.resetCrossbow();
return <ColorsList switchColor={this.props.switchColor} {...props} />
}
showComponentToRender(name) {
if (name === 'features') {
this.setState({
showComponent: this.showFeatures({additional: 'features adds'})
});
} else {
this.setState({
showComponent: this.showColors({additional: 'colors adds'})
})
}
}
render() {
return (
<div id="features-menu-wrapper">
<nav id="features-menu">
<li onClick={() => this.showComponentToRender('features')}>FEATURES</li>
<li onClick={() => this.showComponentToRender('colors')}>COLORS</li>
<li onClick={() => this.props.resetCrossbow()}>RESET A4</li>
</nav>
<div id="component-wrapper">
{this.state.showComponent}
</div>
</div>
);
}
}
const props = {
resetCrossbow: () => null,
switchColor: () => null,
updateCad: () => null,
resetFeatures: () => null
}
ReactDOM.render(<FeaturesMenu {...props}/>, document.querySelector('root'))
<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>
<root/>
You should not save the entire component in your state. Just set a string related to it and as the value changes, the FeaturesMenu will react and
call the function to render the correct component. Obviously, this code can be changed, but I think I've made my point. =)
const FeaturesList = props => (<div>Features List</div>);
const ColorsList = props => (<div>Colors List</div>);
class FeaturesMenu extends React.Component {
constructor(props) {
super(props);
this.state = {
currentComponent: 'Features'
};
this.showFeatures = this.showFeatures.bind(this);
this.showColors = this.showColors.bind(this);
}
showFeatures() {
return (<FeaturesList
updateCad={this.props.updateCad}
resetFeatures={this.props.resetFeatures}
/>);
}
showColors() {
this.props.resetCrossbow();
return <ColorsList switchColor={this.props.switchColor} />
}
showComponentToRender(name) {
this.setState({ currentComponent: name })
}
render() {
return (
<div id="features-menu-wrapper">
<nav id="features-menu">
<li onClick={() => this.showComponentToRender('Features')}>FEATURES</li>
<li onClick={() => this.showComponentToRender('Colors')}>COLORS</li>
<li onClick={() => this.props.resetCrossbow()}>RESET A4</li>
</nav>
<div id="component-wrapper">
{this[`show${this.state.currentComponent}`]()}
</div>
</div>
);
}
}
// for testing purposes
const props = {
resetCrossbow: () => {},
switchColor: () => {},
updateCad: () => {},
resetFeatures: () => {}
}
ReactDOM.render(<FeaturesMenu {...props}/>, document.querySelector('main'))
<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>
<main/>
I have a parent/child component:
class Input extends React.Component {
constructor(props) {
super(props);
this.state = {value: this.props.value};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
// event is persisted, used to update local state
// and then call parent onChange callback after local state update
e.persist();
this.setState(
{value: e.target.value},
() => this.props.onChange(e)
);
}
render() {
return (<input ... onChange={this.handleChange} />);
}
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {modified: false};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const {name, value} = e.target;
console.log(`${name}: ${value}`);
// the two line execute fine, and everything works ok
// but as soon as I add the bottom on, Input no longer updates!
this.setState({modified: true});
}
render() {
return (
<Input ... onChange={this.handleChange}
style={{backgroundColor: this.state.modified?"red":"blue"}}
/>
);
}
}
So as soon as I do a setState on the parent, the child component no longer renders properly. Why? Does it have something to do with the event object or the fact that the parent event handler is called from the child event handler?
Use this (add spaces before and after ?):
style={{backgroundColor: this.state.modified ? "red" : "blue"}}
instead of this:
style={{backgroundColor: this.state.modified?"red":"blue"}}
After this change your example works fine:
class Input extends React.Component {
constructor(props) {
super(props);
this.state = {value: this.props.value};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
// event is persisted, used to update local state
// and then call parent onChange callback after local state update
e.persist();
this.setState(
{value: e.target.value},
() => this.props.onChange(e)
);
}
render() {
return (<input style={this.props.style} onChange={this.handleChange} />);
}
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {modified: false};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const {name, value} = e.target;
console.log(`${name}: ${value}`);
// the two line execute fine, and everything works ok
// but as soon as I add the bottom on, Input no longer updates!
this.setState({modified: true});
}
render() {
return (
<Input onChange={this.handleChange}
style={{backgroundColor: this.state.modified ? "red":"blue"}}
/>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('container')
);
<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="container">
<!-- This element's contents will be replaced with your component. -->
</div>