Sasha Sedova
Sasha Sedova

Reputation: 115

Why component to not re-render when props change?

I have problem that render method doesnt run when the props value is changed. What am I doing wrong? I tried using componentwillrecieveprops but it also doesnt run.

ChildComponent:

 state = {
    data: this.props.populatedWords,
    allSelected: false,
    res: null,
    textAreaVal: null,
    editMode: new Array(this.props.populatedWords.length).fill(false),
    entityList: [],
    selectedEntity: [],
    parts: [],
    final: null,
    entityObject: null,
    sendToUpdateEntity: null,
    arr: JSON.parse(localStorage.getItem('intents'))[localStorage.getItem('intent')],
    selectedValue: null,
    textInput: "",
    token: JSON.parse(localStorage.getItem('user')).tokens.training
};



componentWillReceiveProps(nextProps) {
    console.log("i am called")
    // You don't have to do this check first, but it can help prevent an unneeded render
    if (nextProps.words !== this.state.data) {
        this.setState({ data: nextProps.words });
    }
}

render() {

    return (
        <Card className={classes.root} style={{maxWidth: '100%'}}>
            <NoRazmetkaDialog ref={this.dialog}/>
            <NoEntityDialog ref={this.dialogE}/>
            <HalfRazmetkaDialog ref={this.dialogHalf}/>
            <CardHeader action={<Grid container>
                <Grid item style={{display: 'flex'}}>
                    <Tooltip>
                        <FilterOptions updateSelected={this.updateSelectedValue}/>
                    </Tooltip>
                    <TextField variant="standard" style={{paddingTop: '10px'}} onChange={e => {
                        this.setState({textInput: e.target.value});
                    }}/>
                </Grid>
            </Grid>}/>
            <div className={classes.tableWrapper}>
                <Table className={classes.table} aria-labelledby="tableTitle">
                    <IntentTableHead data={this.state.data} updateAllSelected={this.updateAllSelected}
                                     allSelected={this.state.allSelected} updateData={this.updateData}
                                     sendToDialogflow={this.sendToDialogFlow} updateEntity={this.updateEntity}
                                     entityObject={this.state.entityObject}/>
                    <TableBody>
                        {this.state.data.map((val, i) => {
                            return (
                                <TableRow hover>
                                    <TableCell padding="checkbox">
                                        <Checkbox checked={this.state.data[i].checked}
                                                  onChange={this.addCheckedPhrase(i)}/>
                                    </TableCell>
                                    {!this.state.editMode[i] &&
                                    <TableCell onClick={this.changeEditMode(i)}>
                                        {val.word}
                                    </TableCell>}
                                    {this.state.editMode[i] &&
                                    <TableCell>
                                        <TextField
                                            multiline
                                            defaultValue={val.word}
                                            className={classes.textField}
                                            margin="none"
                                            variant="outlined"
                                            value={this.state.textAreaVal}
                                            onChange={e => this.handleChange(e, i, 'word')}
                                        />
                                        <Button onClick={this.changeEditMode(i)}>OK</Button>
                                    </TableCell>
                                    }
                                    <TableCell>
                                        {array[localStorage.getItem('intent')].display_name}
                                    </TableCell>
                                    {this.state.data[i].test === null &&
                                    <TableCell>
                                        Тестировать
                                    </TableCell>}
                                    {this.state.data[i].test !== null &&
                                    <TableCell>
                                        {this.state.data[i].test}
                                    </TableCell>}
                                    <TableCell>
                                        <Select value={this.state.data[i].entity}
                                                onChange={e => this.handleChange(e, i, 'entity')}
                                                inputProps={{name: "data"}}>
                                            {this.state.entityList.map((val, i) => {
                                                return (<MenuItem value={val} key={i}>{val}</MenuItem>)
                                            })}
                                        </Select>
                                    </TableCell>
                                    <TableCell>
                                        <Button onClick={this.updateIntent(i)}>Обучить</Button>
                                    </TableCell>
                                    <TableCell>
                                        <IconButton onClick={this.deleteRow(i)}>
                                            <ClearIcon/>
                                        </IconButton>
                                    </TableCell>
                                </TableRow>
                            );
                        })}
                    </TableBody>
                </Table>
            </div>
        </Card>
    );
}

Parent component:

 render() {

    return (
        <div>
            <PositionedDialog ref={this.dialog} selectedWord={this.state.selectedWord} textAreaVal={this.state.textAreaVal} updateRes={this.updateRes}/>
            <IconButton variant="contained"
                        color="primary"
                        component={Link} to="/app/intent"
                        onClick={this.backToComponent}
            >
                <KeyboardArrowLeft/>
            </IconButton>
            <Paper>
                <Toolbar>
                    <Grid container alignItems="center">
                        <Grid item xs alignItems="center">
                            <TextField
                                fullWidth
                                onFocus
                                id="help"
                                InputProps={{
                                    disableUnderline: true
                                }}
                                value={this.state.textAreaVal}
                                onKeyPress={e => {
                                    if (e.key === 'Enter') {
                                        this.findSelectedText();
                                    }
                                }}
                                onChange={e => {
                                    this.setState({textAreaVal: e.target.value});
                                }}
                            />
                        </Grid>
                    </Grid>
                </Toolbar>
            </Paper>
            <Paper style={{marginTop: "20px", overflow: "hidden"}}>
                {this.state.generator > 0 && this.state.populatedWords !== null &&
                <IntentTable populatedWords={this.state.populatedWords}/>}
            </Paper>
        </div>
    );
}

this.state.data form a table. and when my this.props.words is updated it does not add row to the table. I see that the problem is with it.

Upvotes: 0

Views: 623

Answers (3)

Junius L
Junius L

Reputation: 16122

to avoid using lifecycle methods, don't save your props to state in your child component. Remove data and editMode from state.

In your child render access the props directly

render() {
 const data = this.props.populatedWords;
 const editMode = new Array(this.props.populatedWords.length).fill(false);
 ...
}

Upvotes: 0

Ragnar
Ragnar

Reputation: 88

First of all, I think you should be using getDerivedStateFromProps as componentWillReceiveProps is deprecated. To address your issue, regarding your componentWillReceiveProps, it appears you're comparing this.state.data of your child with nextProps.words, yet it appears to me you're sending : <IntentTable populatedWords={this.state.populatedWords}/> so your prop name is populateWords. Try changing this and keep me updated!

Upvotes: 0

Isaac Suarez
Isaac Suarez

Reputation: 84

this.state.data is not being used in your render method

Upvotes: 1

Related Questions