This is driving me nuts! I have tried all those tricks to get this data to render using lifecycle methods to compare prop data to current state of the row data in my component but it would seem that maybe React Grid with the row prop is not updating because I can see the console log of the rows with data in my console. It has data but it's showing 'no data' in my table which means when my table rendered there must have been 'no data'. Now if I make simple change to the component, hit save, its updates and boom i see 3 entries in the table. Which oddly now there are 6 entries in my console in the array.
export default class Demo extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
columns: [
{ name: 'teamName', title: 'Team' },
{ name: 'profilePic', title: 'Avatar' },
{ name: 'score', title: 'Score' },
{ name: 'profileName', title: 'profileName' },
{ name: '', title: 'Rank' }
],
rows: [],
pageSizes: [5, 10, 15],
currentPage: 0,
loading: true,
counter: 0
};
}
componentWillMount() {
this.getRows();
}
componentDidMount() {
this.getRows();
}
getRows = () => {
this.setState({
rows: this.props.league
});
};
// static getDerivedStateFromProps(props, state) {
// if (props.league.length !== state.rows.length) {
// return {
// rows: props.league
// };
// }
// return null;
// }
// componentDidMount() {
// console.log("NP1::",this.props.league)
// this.setState({rows: this.props.league})
// }
// componentDidUpdate(nextProps, prevState) {
// if(nextProps.league!==prevState.rows){
// //Perform some operation here
// console.log("NP2::",this.props.league)
// this.setState({rows: this.props.league});
// this.classMethod();
// }
// }
// static getDerivedStateFromProps(nextProps, prevState){
// if(nextProps.league!==prevState.rows){
// console.log("NP::",nextProps.league)
// return{
// rows: nextProps.league
// }
// return
// }
// else return null;
// }
// componentDidUpdate(nextProps, prevState) {
// if(nextProps.league!==prevState.rows){
// //Perform some operation here
// console.log("NP2::",this.props.league)
// this.setState({rows: this.props.league});
// this.classMethod();
// }
// }
// componentWillReceiveProps(nextProps) {
// console.log("NP::",nextProps.league+"----"+this.props.league);
// if (nextProps.league !== this.props.league) {
// console.log("NP2::",nextProps.league)
// this.setState({rows: nextProps.league})
// }
// }
// componentWillUpdate(nextProps, nextState) {
// console.log("NP::", nextProps.league + "----" + this.state.rows);
// if (nextProps.league !== this.state.rows) {
// this.setState({ rows: nextProps.league })
// }
// }
render() {
const { rows, columns } = this.state;
console.log("STATEDATA::", this.state)
return (
<Paper>
<Grid
rows={rows}
columns={columns}
>
<RowDetailState />
<Table
cellComponent={Cell}
/>
<TableHeaderRow />
<TableRowDetail
contentComponent={RowDetail}
/>
</Grid>
{/* <PagingPanel /> */}
</Paper>
);
}
}
I've left in the commented code so you can see the LF methods I've played with. Here is what the first render looks like with no data and the console log of of my state data that includes rows.
My initial state of rows is [] so we know setState happened. Why is that not triggering a render in this component. I saw some posts about this with Ag Grid but is there any known issues with the React grid and getting it to render properly?
As mentioned, in Vs code, if I just do a line return (or make any change) and save. The component updates. I will have 3 entries render and 6 in the console array as seen here.
Adding this so you can see state an league props at same time.
Here is the parent Component
class LeaguePage extends Component {
static propTypes = {
loadLeague: PropTypes.func.isRequired,
}
constructor(props) {
super(props)
this.state = {
};
}
componentWillMount() {
this.props.loadLeague();
}
render() {
console.log("LEAGUEPROPS::",this.props);
return (
<div className="g-row">
<div className="g-col">
<h1>LeaguePage</h1>
{/* <LeagueTable {...this.props} /> */}
<br />
<br />
<RgDetail {...this.props} rows={this.state.rows} />
<br />
<br />
{/* <RgTable /> */}
<br />
<br />
<br />
</div>
</div>
)
}
}
const mapStateToProps = (state, ownProps) => {
console.log("MYSTATE::",state)
return {
league: LeagueSelector(state),
}
}
const mapDispatchToProps = Object.assign(
{},
leagueActions
);
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(LeaguePage));
An the selector for league
import { createSelector } from 'reselect';
import _ from 'lodash';
var data = [];
export function getLeague(state) {
if (state.league) {
return state.league;
}
}
function transform(UserRecord) {
const outerObj = UserRecord[Object.keys(UserRecord)[0]];
data.push(outerObj);
return data
}
export function getSortedLeague(state) {
if (state.length > 1) {
state.map(x => transform(x));
return data;
}
else
return data;
}
//=====================================
// MEMOIZED SELECTORS
//-------------------------------------
export const LeagueSelector = createSelector(
getLeague,
getSortedLeague
);
So this was lesson learned the hard way. All this time I was just returning may payload in my reducer (not replacing state with new state) then in the selector (seen above) I was deriving a new bit of state from that. Bad pattern or practice I guess you could say. I lost myself and tried to get to fancy with my use of selectors.
My old reducer looked like
const user = [{
UID: {
Key: {
profileName: '',
profilePic: '',
score: 0,
teamKeysTier1: '',
teamKeysTier2: '',
teamName: '',
uid: ''
}
}
}];
export function leagueReducer(state = user, {payload, type}) {
switch (type) {
case LOAD_LEAGUE_SUCCESS:
console.log("REDPAYLOAD::",payload)
return payload;
default:
return state;
}
}
I basically forget the basic principles of reducers where you should create new bits of state, your store updates and that will in turn tell the connected components you have new data. This 'connected' wiring was not working in my case I believe because I was not creating/replace in my reducer. So I basically took everything I was doing in my selector (seen above), moved it to my reducer and I'm creating a new bit piece of state using Object.Assign (I know it's a bit terse but for now I"m fine with terse)
Here is my new reducer now.
import { LOAD_LEAGUE_SUCCESS } from '../actions/actionTypes';
const user = [{
profileName: 'FEKing',
profilePic: '',
score: 100,
teamKeysTier1: '',
teamKeysTier2: '',
teamName: 'TheCreator',
uid: ''
}];
export function leagueReducer(state = user, {payload, type}) {
switch (type) {
case LOAD_LEAGUE_SUCCESS:
payload.map(x => {
const outObj = x[Object.keys(x)[0]];
state.push(outObj);
})
console.log("user::",state)
return Object.assign([], state);
default:
return state;
}
}
Now my connected components update and I get my data loading in my table. Basically because of Object.assign([], state)
:)