1

I am new to react and making a little app to learn the library and way of thinking.
But I ran into a problem which has me completely stomped...

I have the root components that contains a list of tasks. I pass these tasks to a custom component to render them into a groups like so:
<TasksView tasks={this.state.tasks}></TasksView>
Where this.state.tasks is an array containing all the current tasks.

But the problem is that my TaskView component never seems to receive these tasks...

See below for the complete code:

ROOT:

class App extends Component<{}, IAppState> {

    constructor(props: any) {
        super(props);

        this.state = {
            taskCategories: [],
            tasks: [],
            currentTask: {}
        };
    }

    testing() {
        this.setState((prev: IAppState) => {
            return {
                tasks: [...prev.tasks, {
                    index: 0,
                    timespan: [TimeTypes.Day, TimeTypes.Week, TimeTypes.Month, TimeTypes.Year][Math.round(Math.random() * 9)],
                    name: '',
                    repeatAmount: 0,
                    repeatDelay: 0,
                    category: {
                        id: 0,
                        color: "",
                        name: ""
                    },
                    onComplete: function (index: number): void {
                        throw new Error('Function not implemented.');
                    }
                }]
            }
        });
    }


    render() {
        console.log("tasks count in parent: ", this.state.tasks.length); //<-- console.log A
        return (
            <SafeAreaView style={styles.container}>
                <TasksView tasks={this.state.tasks}></TasksView>
                <TouchableOpacity
                    onPress={this.testing.bind(this)}
                    style={styles.createTask}
                >
                </TouchableOpacity>
            </SafeAreaView>
        )
    }
};

TASKSVIEW:

class TasksView extends Component<TasksViewProps, any> {

    taskGroups: TasksGroupData[];
    stickyIndices: number[];

    constructor(props: TasksViewProps) {
        super(props);

        console.log("props should be updated..."); //<-- console.log B
        console.log(props.tasks.length);           //<-- console.log C

        this.taskGroups = [];
        this.stickyIndices = [];
    }

    render(): ReactNode {
        return [
            <Text style={tasksViewStyle.title}>Your Goals</Text>,
            <ScrollView
                stickyHeaderIndices={this.stickyIndices}
                showsVerticalScrollIndicator={false}
                style={tasksViewStyle.scrollView}
            >
                {this.taskGroups.map((group: TasksGroupData, index: number) =>
                    <TasksGroup key={index} timespan={group.timespan} tasks={group.tasks}></TasksGroup>
                )}
            </ScrollView>
        ];
    }
}

I have left out all the interface definitions and some helper functions since they would not be relevant to the problem at hand.

So what i would expect is every time console.log A gets executed console.log B and C would also be executed but this is not the case.
See here a screenshot of current console.log sequence.
enter image description here

If any additional information is required let me know so I can update the question.

FutureCake
  • 2,614
  • 3
  • 27
  • 70
  • Hey there, the `constructor` does not re-run each time a component re-renders - React may re-use the same class instance across renders. Instead, to check the values, try moving your logging to [componentDidUpdate](https://reactjs.org/docs/react-component.html#componentdidupdate) - I am not sure if you have an actual issue with your UI, or just the logging is not as you expected, but this should fix the logging :) – deeBo Jan 17 '22 at 22:40
  • Alright cool thanks was not aware of this. No issues with the UI since there isn't one yet :p only at the logging state :) Just curious you said that react may re-use the same class instances multiple times across rendering. Is that always the case or under what conditions does this happen? Since that would be important to know if you rely on class variables to store data across multiple re-renders. – FutureCake Jan 17 '22 at 22:45
  • 1
    @deeBo the componentDidUpdate did fix the logging thanks :) write it as an answer if you want than I will for sure upvote and accept it! – FutureCake Jan 17 '22 at 22:50
  • 1
    Great! I had to double-check the docs there, but it is actually guaranteed to keep the same class instance while your component is mounted - I've posted the updated info in an answer :) – deeBo Jan 17 '22 at 22:56

1 Answers1

1

The constructor is only run once when your component is first mounted, because React re-uses the same class instance for the lifetime of the component (see these docs). This is why you're not seeing your logging calls after they are initially run once.

For logging that runs on each render, you could move your console.logs into componentDidUpdate.

deeBo
  • 836
  • 11
  • 24