I am fetching an array with single object from redux store.
this.props.license :[0: {id: 24, domain: "xyz.com", app_url: "https...", purchase_code: "395"}]
And then creating a form to update the value in the react form.
But when trying to change the value the onChange
event is only occurring once.
I am managing a new state in the react component to save the changes that I am doing on onChange
event.
Is this a correct way in which I am coding?
import React ,{Component} from 'react';
import {connect} from 'react-redux';
import * as actionCreators from '../../store/actions/index';
import Spinner from '../../components/Spinner/Spinner';
const DATABASE_LABELS={
id:'ID',
domain:'Domain',
app_url:'APP URL',
purchase_code:'Purchase Code',
}
class editLicense extends Component {
constructor(props){
super(props);
this.state={
editLicense:{}
}
}
onChangeHandler=(event, type)=>{
// [event.target.name]=[event.target.value]
let newLicense={...this.state.editLicense}
newLicense[type]=event.target.value
console.log(newLicense)
console.log('before',this.state.editLicense)
this.setState({
editLicense :{
...this.state.editLicense,
[event.target.name]:event.target.value
}
})
console.log(this.state.editLicense)
}
componentDidMount=()=>{
this.props.viewLicenceDetails(this.props.token, this.props.match.params.id)
this.setState({
editLicense:this.props.licenses[0]
})
console.log(this.state.editLicense)
}
render(){
let formdata=<Spinner/>;
if(!this.props.loading){
let license=Object.keys(this.props.licenses[0])
.map(key=>{
return [
key,
this.props.licenses[0][key]
]
})
let form=license.map((p, index)=>{
return(
<div className="form-group" key={p[0]}>
<label htmlFor={p[0]}> {DATABASE_LABELS[p[0]]} </label>
<input type="text" className="form-control"
id={p[0]}
value={p[1]}
name={p[0]}
onChange={(event) => this.onChangeHandler(event, p[0])} />
</div>)
})
formdata=(
<form>
{form}
<button type="submit" className="btn btn-primary">Submit</button>
</form>
)
}
return(
<div className="container">
{formdata}
</div>
)}
}
const mapStateToProps = (state)=>{
return({
token:state.auth.idToken,
licenses:state.license.licenses,
loading:state.license.loading,
err:state.license.error
})
}
const mapDispatchToProps = dispatch=>{
return({
updateLicenseData:(token, type, newVal)=>dispatch(actionCreators.updateLicense(token, type, newVal)),
viewLicenceDetails:(token, id)=>dispatch(actionCreators.fetchOneLicense(token, id))
})
}
export default connect(mapStateToProps, mapDispatchToProps)(editLicense);
The question title is a little misleading. Currently, your state is not fully managed by Redux, but only initially fetched from the Redux state.
You are currently:
componentDidMount
.value
from the props (from the Redux state).onChange
-> onChangeHandler
.(2) is your problem currently. Your props are not currently being changed (since you're not calling any Redux actions), so the value of your input
element is never changing. Its a little unintuitive, but this results in changes only being detected once.
You need to populate your input value
prop using your state. In your render()
function, try replacing instances of this.props.licenses[0]
with this.state.editLicense
:
if(!this.props.loading){
let license=Object.keys(this.state.editLicense)
.map(key=>{
return [
key,
this.state.editLicense[key]
]
})
...
}
This way, when your state is updated, the 'current' value of the form will be updated on re-render, and the input
component will be fully controlled.
As a side note:
this.setState({
editLicense:this.props.licenses[0]
})
console.log(this.state.editLicense)
This is not guaranteed to work. setState
should typically be considered asynchronous. If you want to do something in response to an updated state outside of the render cycle, you should provide a callback to setState
:
this.setState({
editLicense:this.props.licenses[0]
},
() => console.log(this.state.editLicense)
);