I am trying to pass data from one component to another. but it has no parent child relation and it is independent from each other. i am able to set the state but problem is after clicking enter my text data get cleared. not sure why,
export class EmpSearch extends React.Component {
// Not needed anymore as state going to Redux and not local component state
/*
constructor(props) {
super(props);
this.state = {
Empnumber: ''
};
}
*/
EmpSearch = (e) => {
if (e.key === 'Enter') {
browserHistory.push('/Emp/' + e.target.value);
}
}
updateEmpNumber(e) {
this.props.dispatch({
type: 'UPDATE_EMP_NUMBER',
payload: e.target.value
});
}
render() {
return (
<div className="row">
<form>
<div className="form-group">
<label htmlFor="Empnumber">Emp Number</label>
<input type="text" className="form-control" id="Empnumber" placeholder="Emp Number" value={this.props.Empnumber} onChange={this.updateEmpNumber.bind(this)} onKeyPress={this.EmpSearch}/>
</div>
</form>
</div>
);
}
}
function mapStateToProps(state){
return {
Empnumber: state.Empnumber
}
}
export default connect(mapStateToProps)(EmpSearch);
browserHistory.push('/Emp/' + e.target.value); is probably causing your component to be unmounted and remounted.
You say the value is stored in the redux state, but I can't see where you update the redux state.
Related
i found a gist about how to pass state between two components.
Here the jsbin
But how about the multi state?
I want two input fields and show the entered text in other components when i edit it.
i tried edited like this
this.state = {
fieldVal: "" //first input state
otherFieldVal: "" //second
}
and
//input onChange
onUpdate = name => (event) => {
this.setState({ [name]: event.target.value });
};
with no luck.
How can i made it work on multi state for multi input fields ?
Don't need to keep state in both Child and parent. You can write your child component like below, and you can access tow states dynamically by using data-attirb or you can folloe #Isaac 's answer.Keep the state in Child and pass state to Parent or keep the event to Parent from Child.
export class Child extends React.Component {
update = (e) => {
this.props.onUpdate(e.target)
};
render() {
return (
<div>
<h4>Child</h4>
<input
type="text"
placeholder="type here"
onChange={this.update}
data-state = "fieldVal"
value={this.props.fieldVal}
/><br/><br/>
<input
type="text"
placeholder="type here"
onChange={this.update}
data-state = "otherFieldVal"
value={this.props.otherFieldVal}
/>
</div>
)
}
}
export class OtherChild extends React.Component {
render() {
return (
<div>
<h4>OtherChild</h4>
Value in OtherChild Props passedVal1: {this.props.passedVal1} <br/>
Value in OtherChild Props passedVal2: {this.props.passedVal2}
</div>
)
}
}
and in parent :
class App extends Component {
onUpdate = (data) => {
this.setState({
[data.dataset.state]: data.value
})
};
render() {
return (
<div>
<h2>Parent</h2>
Value in Parent Component State fieldVal: {this.state.fieldVal} <br/>
Value in Parent Component State otherFieldVal: {this.state.otherFieldVal}
<br/>
<Child onUpdate={this.onUpdate} fieldVal= {this.state.fieldVal} otherFieldVal ={this.state.otherFieldVal}/>
<br />
<OtherChild passedVal1={this.state.fieldVal} passedVal2={this.state.otherFieldVal}/>
</div>
);
}
}
demo
renderInput = (prop) => {
return (
<Input
onChange={(event) => {
this.setState({ [prop]: event.target.value });
}}
/>
)
}
render() {
<div>
{this.renderInput('name')}
{this.renderInput('age')}
</div>
}
We can set a renderInput method and render different input using parameter to achieve your objective
I want to set the state value of children component using props and then display the same for the respective form field. I did that inside the componentDidMount() but it doesn't work.
Code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
tweetCount: this.props.tweetCount
};
}
componentDidMount() {
const tweetCount = this.props.tweetCount;
this.setState({ tweetCount });
}
render() {
return (
<React.Fragment>
<Form>
<FormGroup>
<Label for="tweetCount">
Tweets per Column (between 1 and 30):
{this.state.tweetCount}
</Label>
<Input
id="tweetCount"
type="range"
min="1"
max="30"
value={this.state.tweetCount}
onChange={this.changeTweetCount}
step="1"
/>
</FormGroup>
</Form>
</React.Fragment>
);
}
}
If you use React that version is upper than 16.3 then use getDerivedStateFromProp so inside of using componentDidMount or componentWillReceiveProps use this code :
static getDerivedStateFromProps(props, state)
{
return{
tweetCount:props.tweetCount
}
}
I am building a basic react app combined with the Pokeapi. Whenever the user types something in the input field of my pokedex, I want to update the state to then (onSubmit) find this pokemon in the Pokeapi.
Whenever I log the state (in the state update function), it logs the state -1 character as typed in the input field.
Printscreen of result
Snippet of component:
import React, { Component } from 'react';
export default class Pokedex extends Component {
constructor(props) {
super(props);
this.state = {
pokemon: "",
result: {}
}
}
setPokemon(value) {
this.setState({
...this.state.pokemon,
pokemon: value.toLowerCase()
});
console.log(this.state.pokemon);
}
render() {
return (
<div className="container-fluid">
<div className="pokedex row">
<div className="col-half left-side">
<div className="screen"/>
<div className="blue-button"/>
<div className="green-button"/>
<div className="orange-button"/>
</div>
<div className="col-half right-side">
<input type="text" placeholder="Find a pokemon" onChange={(e) => this.setPokemon(e.target.value)}/>
</div>
</div>
</div>
)
}
}
Why does this happen?
setState is an async function. That means using console.log immediately after setState will print the last state value. If you want to see the latest updated value then pass a callback to setState function like this
setPokemon(value) {
this.setState({pokemon: value.toLowerCase()},
() => console.log(this.state.pokemon));
}
This first way you can directly set the state of pokemon inside of the input.
<input type="text" placeholder="Find a pokemon" onChange={(e) => this.setState({ pokemon:e.target.value }) }/>
remove the function set pokemon.
setPokemon(value) {
this.setState({
...this.state.pokemon,
pokemon: value.toLowerCase()
});
console.log(this.state.pokemon);
}
theres no reason to use the spread operator, all you would simply do if you did want to use a setter is,
setPokemon = (value) => {
this.setState({ pokemon:value })
}
but even then the first way is better.
Theres also
setPokemon = (e) => {
this.setState({ pokemon:e.target.value })
}
then in input <input onChange={this.setPokemon()} />
I am sending a callback function from a parent to a child component, and although the parent successfully updates it's state based on input provided to the child, it immediately reverts back to initial state, thus resulting in the browser briefly flashing the input that was provided and then displaying the initial state. What is the fix for this? Here is my code:
Parent:
class App extends Component {
constructor() {
super()
this.state = { item: '' }
this.getItem=this.getItem.bind(this);
}
getItem(val) {
this.setState({
item: val
})
console.log(this.state.item);
}
render() {
return (
<div className="App">
<Input getItem={this.getItem} />
<h2>{this.state.item}</h2>
</div>
);
}
}
Child:
class Input extends Component {
constructor(props) {
super(props)
this.state = { value: '' }
this.handleChange=this.handleChange.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({
value: e.target.value
})
console.log(this.state.value)
}
handleSubmit(e) {
{this.props.getItem(this.state.value)};
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
<input type="text" name={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="+" />
</form>
</div>
)
}
}
I was able to solve this by using e.preventDefault() in the handleSubmit function.
Currently in react js, when I want to bind a text area or an input with a "state", I will need to set the onChange method and setState() everytime user type in a single letter
I heard if you setState react js refresh and re-render everything in this component
Is there any more efficient way to do so? using "shouldComponentUpdate" will be improper in this case since if I don't make "state" update, all user input will be stuck..
Well, that's how you implement controlled input elements in React.
However, if performance is a major concern of yours, you could either isolate your input element in a separate stateful component, hence only triggering a re-render on itself and not on your entire app.
So something like:
class App extends Component {
render() {
return (
<div>
...
<MyInput />
...
</div>
);
}
}
class MyInput extends Component {
constructor() {
super();
this.state = {value: ""};
}
update = (e) => {
this.setState({value: e.target.value});
}
render() {
return (
<input onChange={this.update} value={this.state.value} />
);
}
}
Alternatively, you could just use an uncontrolled input element. For example:
class App extends Component {
render() {
return (
<div>
...
<input defaultValue="" />
...
</div>
);
}
}
Though, note that controlled inputs are generally recommended.
As #Chris stated, you should create another component to optimize the rerendering to only the specified component.
However, there are usecases where you need to update the parent component or dispatch an action with the value entered in your input to one of your reducers.
For example I created a SearchInput component which updates itself for every character entered in the input but only call the onChange function only if there are 3 characters at least.
Note: The clearTimeout is useful in order to call the onChange function only when the user has stopped typing for at least 200ms.
import React from 'react';
class SearchInput extends React.Component {
constructor(props) {
super(props);
this.tabTimeoutId = [];
this.state = {
value: this.props.value,
};
this.onChangeSearch = this.onChangeSearch.bind(this);
}
componentWillUpdate() {
// If the timoutId exists, it means a timeout is being launch
if (this.tabTimeoutId.length > 1) {
clearTimeout(this.tabTimeoutId[this.tabTimeoutId.length - 2]);
}
}
onChangeSearch(event) {
const { value } = event.target;
this.setState({
value,
});
const timeoutId = setTimeout(() => {
value.length >= this.props.minSearchLength ? this.props.onChange(value) : this.props.resetSearch();
this.tabTimeoutId = [];
}, this.props.searchDelay);
this.tabTimeoutId.push(timeoutId);
}
render() {
const {
onChange,
minSearchLength,
searchDelay,
...otherProps,
} = this.props;
return <input
{...otherProps}
value={this.state.value}
onChange={event => this.onChangeSearch(event)}
/>
}
}
SearchInput.propTypes = {
minSearchLength: React.PropTypes.number,
searchDelay: React.PropTypes.number,
};
SearchInput.defaultProps = {
minSearchLength: 3,
searchDelay: 200,
};
export default SearchInput;
Hope it helps.
You need to bind the onChange() event function inside constructor like as code snippets :
class MyComponent extends Component {
constructor() {
super();
this.state = {value: ""};
this.onChange = this.onChange.bind(this)
}
onChange= (e)=>{
const formthis = this;
let {name, value} = e.target;
formthis.setState({
[name]: value
});
}
render() {
return (
<div>
<form>
<input type="text" name="name" onChange={this.onChange} />
<input type="text" name="email" onChange={this.onChange} />
<input type="text" name="phone" onChange={this.onChange} />
<input type="submit" name="submit" value="Submit" />
</form>
</div>
);
}
}
You don't need a complicated react solution to this problem, just a little common sense about when to update state. The best way to achieve this is to encapsulate your setState call within a timeout.
class Element extends React.Component {
onChange = (e) => {
clearTimeout(this.setStateTimeout)
this.setStateTimeout = setTimeout(()=> {
this.setState({inputValue: e.target.value})
}, 500)
}
}
This will only set state on your react element a 500ms after the last keystroke and will prevent hammering the element with rerenders as your user is typing.