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,
}
],
});
}