I have 3 label that can receive input when button clicked and then i need sum from the third input value the code kinda work but instead of getting the sum of the third input it instead it looks like the image below where the input get combined kinda like a string (not sure how to call it). Any help is appreciated What Total looks like
This is my full code
import React, { Component } from 'react';
import './Bootstrap/css/bootstrap.min.css';
class App extends Component {
constructor(){
super();
this.state = {
mahasiswa : [],
tgl : null,
nama : null,
nilai : null,
nilaiArray: []
}
}
setValueState(event){
var value = event.target.value
this.setState({
[event.target.name] : value
})
var nilaiArrayTmp = this.state.nilaiArray;
nilaiArrayTmp.push(value?parseFloat(value).toFixed(2):0)
this.setState({
nilaiArray: nilaiArrayTmp
})
}
addData(){
var data_tmp = this.state.mahasiswa;
data_tmp.push({nim : this.state.tgl, nama : this.state.nama, nilai : this.state.nilai});
this.setState({
mahasiswa : data_tmp
})
}
render() {
const total=(this.state.mahasiswa.reduce((total,{nilai}) => total = total nilai , 0 ));
return (
<div className="container">
<h2><b>Daftar Pengeluaran</b></h2>
<div className="form-container">
<div className="form-group">
<label>Waktu:</label>
<input type="text" name="tgl" value={this.state.tgl} onChange={this.setValueState.bind(this)} className="form-control" />
</div>
<div className="form-group">
<label>Deskripsi:</label>
<input type="text" name="nama" value={this.state.nama} onChange={this.setValueState.bind(this)} className="form-control" />
</div>
<div className="form-group">
<label>Jumlah:</label>
<input type="number" name="nilai" value={this.state.nilai} onChange={this.setValueState.bind(this)} className="form-control" />
</div>
<br />
<button onClick={this.addData.bind(this)} type="button" className="btn btn-primary">Tambah</button>
</div>
<br />
<table className="table">
<thead>
<tr>
<th>No.</th>
<th>Waktu</th>
<th>Deskripsi</th>
<th>Jumlah</th>
</tr>
</thead>
<tbody>
{this.state.mahasiswa.map((mhs, index)=>(
<tr key={index}>
<td>{index 1}</td>
<td>{mhs.tgl}</td>
<td>{mhs.nama}</td>
<td>{mhs.nilai}</td>
</tr>
))}
<tr>
<td></td>
<td></td>
<td>Total:</td>
<td>{total}</td>
</tr>
</tbody>
</table>
</div>
);
}
};
export default App;
CodePudding user response:
Input bydefalult is inputting it as string and setting the state also as a String. Because of that 0 string = string and you are getting a string.
Instead of adding to 0, it is converting 0 to a string and concatenating rest of the values to it.
You can use parseInt or parseFloat accordingly to use it as an Integer and get desired result.
const total=(this.state.mahasiswa.reduce((total,{nilai}) => total parseInt(nilai) , 0 ));
CodePudding user response:
parseFloat(value).toFixed(2) returns a string type, not a number type
setValueState(event){
var value = event.target.value
this.setState({
[event.target.name] : value
})
var nilaiArrayTmp = this.state.nilaiArray;
nilaiArrayTmp.push(value?parseFloat(value).toFixed(2):0) // <-- converted back to string type!
this.setState({
nilaiArray: nilaiArrayTmp
})
}
so in the array reduce callback you are doing string concatenation. To resolve, convert the values back to a number time for addition. Don't mutate the total value being returned, just return the current total value plus the next nilai value.
const total = this.state.mahasiswa.reduce(
(total, { nilai }) => total Number(nilai),
0
);
The state mutations
In both the setValueState and addData handlers you are mutating the state object but directly pushing into the arrays.
setValueState(event) {
var value = event.target.value
this.setState({
[event.target.name] : value
})
var nilaiArrayTmp = this.state.nilaiArray; // <-- reference to state
nilaiArrayTmp.push(value?parseFloat(value).toFixed(2):0) // <-- state mutation!!
this.setState({
nilaiArray: nilaiArrayTmp // <-- reference saved back into state
})
}
addData(){
var data_tmp = this.state.mahasiswa; // <-- reference to state
data_tmp.push({ // <-- state mutation!!
nim: this.state.tgl,
nama: this.state.nama,
nilai: this.state.nilai,
});
this.setState({
mahasiswa: data_tmp // <-- reference saved back into state
});
}
In both cases you should use a functional state update and return a new array reference.
setValueState(event) {
const { name, value } = event.target;
this.setState(prevState => ({
[name]: value,
nilaiArray: [
...prevState.nilaiArray,
value ? Number(value).toFixed(2) : 0,
],
}))
}
addData(){
this.setState({
mahasiswa: [
...prevState.mahasiswa,
{
nim: prevState.tgl,
nama: prevState.nama,
nilai: prevState.nilai,
}
],
});
}
