Reputation:
I'm learning React, but not strong yet. I use a component with form, that recieve data from express backend using axios. There is no problems with get the correct data and render it in the form inputs, but i can't cope how to change input values and post using axios. I read something about handleChange() and other staff, but it's too hard yet.
The JSON looks like this:
{
"data": [
{
"_id": "5d28a6fcec97b111c2f5867d",
"phone": "+1 (111) 111 11 11",
"email": "[email protected]",
"title": "khkjhkjhkj",
"longTitle": "lkjlkjlkjlk",
"introTitle": "Shutruk",
"introLongTitle": "Shutruk-Nahhunte",
"videoLink": "khkjhkjhkj",
"introText": "lkjlkjlkjlk",
"__v": 0
}
]
}
Here is the component:
import React, { Component } from 'react';
import axios from 'axios';
class Misc extends Component {
state = {
data: [],
loading: true,
error: false,
}
componentDidMount() {
axios.get('http://localhost:5555/data')
.then(res => {
const data = res.data.data; // get the data array instead of object
this.setState({ data, loading: false });
console.log(data);
})
.catch(err => { // log request error and prevent access to undefined state
this.setState({ loading: false, error: true });
console.error(err);
})
}
render() {
if (this.state.loading) {
return(
<div>
<p> Loading... </p>
</div>
)
}
if (this.state.error || !this.state.data[0]) { // if request failed or data is empty don't try to access it either
return(
<div>
<p> An error occured </p>
</div>
)
}
return (
<form action="">
<h2 className="center" >Change data</h2>
<div className="center"><img src={require('../img/orn.png')} alt="" className="orn"/></div>
<h5>Phone:</h5>
<input type="text" value={ this.state.data[0].phone } />
<h5>Email:</h5>
<input type="text" value={ this.state.data[0].email } />
<h5>Title:</h5>
<input type="text" value={ this.state.data[0].title }/>
<h5>Longtitle:</h5>
<input type="text" value={ this.state.data[0].longTitle }/>
<h2 className="center" >Intro:</h2>
<div className="center"><img src={require('../img/orn.png')} alt="" className="orn"/></div>
<h5>Title:</h5>
<input type="text" value={ this.state.data[0].introTitle } />
<h5>Longtitle:</h5>
<input type="text" value={ this.state.data[0].introLongTitle } />
<h5>Link to video:</h5>
<input type="text" value={ this.state.data[0].videoLink } />
<h5>Text:</h5>
<textarea name="" id="" cols="30" rows="10" value={ this.state.data[0].introText }></textarea>
<button type="submit" className="btn-large waves-effect waves-light xbutton">Save</button>
</form>
);
}
}
export default Misc;
Many many thanks for any help!))
Upvotes: 1
Views: 2589
Reputation: 6253
One of the major differences between React and Vue/Angular is the focus on one-way databinding. While you supply a value
through state to the input components, they cannot themselves update your state when changes happen.
From the React Docs on Forms:
In HTML, form elements such as
<input>
,<textarea>
, and<select>
typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated withsetState()
.
We call this controlled components. The component state is the single source of truth, and state can only explicitly be changed by setState
. You would typically do this in -- as you said -- a change handler:
class MyForm extends React.Component {
state = {
name: ''
};
handleChange = (evt) => {
// evt is a change event
this.setState({
name: evt.target.value,
});
}
render() {
return (
<input type="text" value={this.state.name} onChange={this.handleChange} />
);
}
}
ReactDOM.render(<MyForm />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
This can of course be cumbersome, especially with many different types of inputs. However it is easy to reason about where changes come from.
You can also use uncontrolled components, where you often supply your inputs with default values. These inputs can change their value, but it will not be reflected in your state. You can use refs to read their value when needed:
class MyForm extends React.Component {
state = {
name: 'Foo'
};
constructor() {
super();
this.inputRef = React.createRef();
}
handleSubmit = (evt) => {
evt.preventDefault();
const name = this.inputRef.current.value;
console.log({ name });
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input ref={this.inputRef} type="text" defaultValue={this.state.name} />
<button type="submit">Submit</button>
</form>
);
}
}
ReactDOM.render(<MyForm />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Upvotes: 1
Reputation: 485
Here is how you can do it.
handleChange(key, value){
const data = this.state.data;
data[0][key] = value;
this.setState({data});
}
handleSubmit(){
// You can make post call here.
}
render() {
if (this.state.loading) {
return(
<div>
<p> Loading... </p>
</div>
)
}
if (this.state.error || !this.state.data[0]) { // if request failed or data is empty don't try to access it either
return(
<div>
<p> An error occured </p>
</div>
)
}
return (
<form action="" onSubmit={this.handleSubmit.bind(this)}>
<h2 className="center" >Change data</h2>
<div className="center"><img src={require('../img/orn.png')} alt="" className="orn"/></div>
<h5>Phone:</h5>
<input type="text" value={ this.state.data[0].phone } onChange={this.handleChange.bind(this, "phone")}/>//Here you have to pass key in this case it's phone
<h5>Email:</h5>
<input type="text" value={ this.state.data[0].email } />
<h5>Title:</h5>
<input type="text" value={ this.state.data[0].title }/>
<h5>Longtitle:</h5>
<input type="text" value={ this.state.data[0].longTitle }/>
<h2 className="center" >Intro:</h2>
<div className="center"><img src={require('../img/orn.png')} alt="" className="orn"/></div>
<h5>Title:</h5>
<input type="text" value={ this.state.data[0].introTitle } />
<h5>Longtitle:</h5>
<input type="text" value={ this.state.data[0].introLongTitle } />
<h5>Link to video:</h5>
<input type="text" value={ this.state.data[0].videoLink } />
<h5>Text:</h5>
<textarea name="" id="" cols="30" rows="10" value={ this.state.data[0].introText }></textarea>
<button type="submit" className="btn-large waves-effect waves-light xbutton">Save</button>
</form>
);
}
}
You can more read it on form control https://reactjs.org/docs/forms.html
Upvotes: 0