For some reason my React component seems to remember its old state when going to another tab and back again, instead of reloading completely.
Basically when I click on the "Create" tab in my navbar and back to the "Board" tab data is populated twice instead of once, see image below. When going back the Board component this.state
has two of each taskIds
, as if it the component state still had the data from the initial page load when loading again. I have a React component looking like this:
const columnOrder = ['todo', 'in-progress', 'in-review', 'done']
const EMPTY_COLUMNS = {
'todo': {
id: 'todo',
title: 'TODO',
taskIds: []
},
'in-progress': {
id: 'in-progress',
title: 'In Progress',
taskIds: [],
},
'in-review': {
id: 'in-review',
title: 'In Review',
taskIds: []
},
'done': {
id: 'done',
title: 'Done',
taskIds: []
}
};
export class Board extends Component {
constructor(props) {
super(props);
this.onLoadEpic = this.onLoadEpic.bind(this);
this.state = {
columnOrder: columnOrder,
columns: {
'in-progress': {
id: 'in-progress',
title: 'In Progress',
taskIds: [],
},
// ...more columns similar to above
},
};
// Load state data on mount
componentDidMount() {
loadEpic(arg1, arg2);
}
// Async function loading items from DB and formatting into useful columns
async loadEpic(arg1, arg2) {
axios.get(...)
.then((response) => {
let data = response.data;
let newTasks = {};
let newColumns = EMPTY_COLUMNS;
data.taskItems.forEach(function(item) {
let id = item.id.toString();
newColumns[item.status]["taskIds"].push(id);
newTasks[id] = {
...item,
id: id
}
});
this.setState({
tasks: newTasks,
columns: newColumns
});
})
}
render() {
// Prints ["7"] on initial load and ["7", "7"] after going back and forth
console.log(this.state.columns["in-progress"].taskIds);
return (
// Simplified, but this is the main idea
<Container>
<DragDropContext onDragEnd={this.onDragEnd}>
{
this.state.columnOrder.map((columnId) => {
const column = this.state.columns[columnId]
const tasks = column.taskIds.map(taskId => this.state.tasks[taskId]
return (
<Column key={column.id} column={column} tasks={tasks}/>
)
}
}
</DragDropContext>
</Container>
)
}
}
and an App.js with Routing looking like this:
export default class App extends Component {
static displayName = App.name;
render () {
return (
<Layout>
<Route exact path='/' component={Board} />
<Route exact path='/create' component={Create} />
</Layout>
);
}
}
Okay, so I figured it out: it's the EMPTY_COLUMNS
constant that is bugging out. When the component is re-rendered, the same EMPTY_COLUMNS
object is referenced - so the constant is being appended to. Instead, I should make a copy of the empty columns:
// Before - same object is being appended to, doesn't work
let newColumns = EMPTY_COLUMNS;
// After - create a deep copy of the constant, does work
let newColumns = JSON.parse(JSON.stringify(EMPTY_COLUMNS));