Reputation: 2922
I have developed a component which receive data from another component (father). The component who receives the data, the first time, show the data correctly, but the second time, don't do it.
The second time the metho componentWillReceiveProps is called and I have implemented this. But, despite that, the data is not refreshed.
To see the data of this second call, I need to send data to component child a third time and in this moment I will see the data of the second call.
The code of the component child is:
import React, {Component} from "react";
import { Button, Spinner } from "react-bootstrap";
import BootstrapTable from 'react-bootstrap-table-next';
import { columnsTTShootingFEB, sortedTTShootingFEB } from "../../FEBCOM/column.tables";
import ToolkitProvider from 'react-bootstrap-table2-toolkit';
import "../../../css/content.css";
/**
* This constat let me have a row with buttons who show or hide columns
*
* @param {*} param0
*/
const CustomToggleList = ({
columns,
onColumnToggle,
toggles
}) => (
<div className="btn-group btn-group-toggle" data-toggle="buttons" style = {{width: 100 + "%"}}>
{
columns
.map(column => ({
...column,
toggle: toggles[column.dataField]
}))
.map((column, index) => {
if (index > 1){
return (<button
type="button"
key={ column.dataField }
className={ `btn btn-success btn-sm ${column.toggle ? 'active' : ''}` }
data-toggle="button"
aria-pressed={ column.toggle ? 'true' : 'false' }
onClick={ () => onColumnToggle(column.dataField) }
>
{ column.text }
</button>)
}
})
}
</div>
);
class TTShooting extends Component{
constructor(props){
super(props);
this.props = props;
this.state = {
loaded: false
};
}
componentDidMount(){
console.log("Componente cargado");
console.log("id_team_club 1: " + this.props.teams_std_stats[0].id_team_club);
this.setState({
loaded: true,
teams_std_stats: this.props.teams_std_stats
});
}
componentWillReceiveProps(nextProps){
this.props = nextProps;
console.log("id_team_club 2: " + this.props.teams_std_stats[0].id_team_club);
this.setState({
teams_std_stats: this.props.teams_std_stats
});
console.log("Componente recibe nuevos datos");
}
render(){
return(
<div>
{
(this.state.loaded) ?
<div>
{
(this.props.language === "es") ?
<div>
<ToolkitProvider
keyField="id_team_club"
data={ this.state.teams_std_stats }
columns={ columnsTTShootingFEB }
columnToggle
>
{
props => (
<div>
<p className = "text-justify" style = {{fontSize: 12 + "pt"}}><b>Nota: </b>Para añadir o eliminar columnas en la tabla basta hacer clic sobre uno de estos botones</p>
<CustomToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
footerClasses = "footer-class"
defaultSorted = { sortedTTShootingFEB }
/>
</div>
)
}
</ToolkitProvider>
</div>
:
<h2>Pendiente de desarrollo</h2>
}
</div>
:
<div style = {{marginTop: 10 + "px"}}>
<Button variant="dark" disabled>
<Spinner
as="span"
animation="border"
size="sm"
role="status"
aria-hidden="true"
/>
<span className="sr-only">
{(this.props.language === "es") ? "Cargando datos ..." : "Loading data ..."}
</span>
</Button>{' '}
<Button variant="dark" disabled>
<Spinner
as="span"
animation="grow"
size="sm"
role="status"
aria-hidden="true"
/>
{(this.props.language === "es") ? "Cargando datos ..." : "Loading data ..."}
</Button>
</div>
}
</div>
)
}
}
module.exports.TTShooting = TTShooting;
This code returns a log when is called the first time and other times. The first time returns:
> id_team_club 1: 769
This is correct. When I send new data is called the method componentWillReceiveProps, I update the props and the state and show the id_team_club of the firs element and this is the same. The method is called twice.
> id_team_club 2: 769
> Componente recibe nuevos datos
> id_team_club 2
> Componente recibe nuevos datos
But, if I send data again, then I show the data of the second send of data in the second call to the function:
> id_team_club 2: 769
> Componente recibe nuevos datos
> **id_team_club 2: 720**
> Componente recibe nuevos datos
What am I doing wrong? How can I update the data of the table?
I have updated the code of componentWillReceiveProps and how I pass the data to the table.
componentWillReceiveProps(nextProps){
if (this.props.teams_std_stats !== nextProps.teams_std_stats) {
console.log("Vamos a modificar el state");
this.setState({
teams_std_stats: nextProps.teams_std_stats
});
}
}
<ToolkitProvider
keyField="id_team_club"
data={ this.state.teams_std_stats }
columns={ columnsTTShootingFEB }
columnToggle
>
{
props => (
<div>
<p className = "text-justify" style = {{fontSize: 12 + "pt"}}><b>Nota: </b>Para añadir o eliminar columnas en la tabla basta hacer clic sobre uno de estos botones</p>
<CustomToggleList { ...props.columnToggleProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
footerClasses = "footer-class"
defaultSorted = { sortedTTShootingFEB }
/>
</div>
)
}
</ToolkitProvider>
But, it doesn't work.
Upvotes: 1
Views: 3661
Reputation: 20440
(Posted a solution on behalf of the question author to move the answer to the answer space).
The problem was due to the data. Because didn't arrive correctly. These data are get it by a query to database after an event and when I assign the id of the element which fire the event this was not assigning correctly to the state.
To assign correctly the value to the state I have to do this:
async handleChange(event){
/**
* If you want to access the event properties in an asynchronous way, you should call event.persist() on the event, which will remove
* the synthetic event from the pool and allow references to the event to be retained by user code.
*/
event.persist();
let season = this.state.seasons.find((item) => {
return parseInt(item.id) === parseInt(event.target.value)
});
this.setState({
itemSelected: season.id,
});
}
Upvotes: 1
Reputation: 12222
Do not mutate the props in lifecycle methods. The render function will always have the updated props, you do not need to set this.props
.
componentWillReceiveProps(nextProps) {
if (this.props.teams_std_stats !== nextProps.teams_std_stats) {
this.setState({
teams_std_stats: nextProps.teams_std_stats
});
}
}
Also setting this.props = props
inside constructor is wrong.
constructor(props){
super(props);
this.state = {
loaded: false
};
}
Upvotes: 1
Reputation: 559
As others have pointed the problem is related to modifying the props, but I also wanted to add that I see no need to take team_std_stats
and to make it part of your component state, you can reference that straight from the props in your render function, why not just do that?
try this line
data={ this.props.teams_std_stats }
instead of
data={ this.state.teams_std_stats }
for your <ToolkitProvider />
implementation.
Hope that helps.
Upvotes: 0
Reputation: 6603
You should not change the props in react, the props of a component are read-only. This expression is incorrect:
this.props = nextProps;
Please read this article about props props-are-read-only
Upvotes: 3