V
V
vertically-challenged2021-10-06 18:49:24
React
vertically-challenged, 2021-10-06 18:49:24

Why doesn't React render the component on state change?

The UserTable file has an addRow function that changes the variable responsible for the number of rows in the table, but after setting a new state, rendering does not occur, and the variable itself changes only after the second click on the button that calls this function. I don't understand how to fix this.

usertable:

import React, {Component} from 'react'
import MocData from '../../MocData.json'
import Table from '../../components/Table/Table'

export default class UsersTable extends Component {
    constructor(props) {
        super(props)
        this.state = {
            data: MocData,
            numberOfRows: MocData.length, 
        }
    }

    addRow = (event) => {
        let numberOfRows = this.state.numberOfRows + 1
        this.setState({
            numberOfRows
        })
        console.log(this.state.numberOfRows)
    }

    render() {
        let tableButtons = [
            {
                content: 'Сохранить таблицу', 
                title: null, 
                type: 'save'
            },
            {
                content: 'Добавить запись', 
                title: null, 
                type: 'add',
                onClickHandler: this.addRow
            }
        ]

        return (
            <Table
                numberOfRows = {this.state.numberOfRows}
                numberOfColumns = {Object.keys(this.state.data[0].data).length}
                columnNames = {Object.keys(this.state.data[0].data)}
                content = {this.state.data}
                tableButtons = {tableButtons}
            />      
        )
    }
}


Table.js:
Here in the createRow() function, the value of the numberOfRows variable is used, it is passed as the first parameter
import React, {Component} from 'react'
import './Table.scss'
import Row from './Parts/Row'
import Button from '../Button/Button'

export default class Table extends Component {
    constructor(props) {
        super(props)
        this.state = {
            numberOfRows: props.numberOfRows, // Число от 0
            numberOfColumns: props.numberOfColumns, // Число от 0
            columnNames: props.columnNames, // Массив строк, например ['Имя1','Имя2']
            content: props.content, // Массив объектов, каждый из которых содержит id и объект data | { id: 1234, data: {name: 'Иван', surname:'Иванов'}}
            tableButtons: props.tableButtons, // Массив объектов с параметрами кнопок, где каждый объект содержит параметры конкретной кнопки
            rowButtons: []
        }
    }

    createButtons = (tableButtons) => {
        let Buttons = []

        tableButtons.map( (item, index) => {
            Buttons.push(
                <Button
                    key = {tableButtons[index].content}
                    title = {tableButtons[index].title}
                    type = {tableButtons[index].type}
                    onClick = {tableButtons[index].onClickHandler}
                >
                    {tableButtons[index].content}
                </Button>        
            )
        })

        return Buttons
    }

    createRow = (counter, content, isHeader = false) => {
        let rows = []
        for (let i = 0; i < counter; i++) {
            if (isHeader) {
                rows.push(
                    <Row
                        key = {counter}
                        numberOfColumns = {this.state.numberOfColumns}
                        content = {content}
                        isHeader = {isHeader}
                    />) 
            } else if (content[i]){
                rows.push(
                    <Row
                        key = {content[i]._id}
                        id = {content[i]._id}
                        numberOfColumns = {this.state.numberOfColumns}
                        content = {content[i].data}
                        isHeader = {isHeader}
                    />) 
            } else {
                rows.push(
                    <Row
                        key = {counter + 1}
                        numberOfColumns = {this.state.numberOfColumns}
                        content = {null}
                        isHeader = {isHeader}
                    />) 
            }
        }
        return (rows)
    }

    render() {
        return (
            <React.Fragment>
                <table className="Table">
                    <tbody>
                        {this.createRow(1, this.state.columnNames, true)}
                        {this.createRow(this.state.numberOfRows, this.state.content)}
                    </tbody>
                </table> 
                <div className="buttonContainer">
                    {this.createButtons(this.state.tableButtons)}
                </div>
            </React.Fragment>
        )
    }
}


Button.js:
import React from 'react'
import './Button.scss'

const Button = props => {
    const cls = `Button ${props.type}`
    return (
        <button 
            className={cls}
            type="button"
            onClick={props.onClick}
            title={props.title}
        >
            <span>{props.children}</span>
        </button>
    )
}

export default Button

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Aetae, 2021-10-06
@vertically-challenged

You are in Table renderuse this.state.numberOfRows, but should this.props.numberOfRows. this.state.numberOfRowsyou set only once at creation (constructor) and never change.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question