Adam Norton
Adam Norton

Reputation: 580

React - Value Re-Render Grandchild Component on Props Change Not Working

I have created a billing calculator for my company. We can select different rates types, "profit", "non-profit", and "existing" for special clients.

A rate type is set, then we choose one of our employees, and it pulls the values in the rate table, plugs it in and does the math based on that employee's billing rate, cost to the company, and number of hours we plug in for that project. It calculates what we will bill, and what the profit will be.

Everything works as expected EXCEPT when I change the rate type on a project, the state does in fact update to the correct type, and I can then select rates, and the numbers shown are correct. But, if I already have an employee set, and it has their rate displayed... these need to dynamically change based on the new rate table as the rate changes.

This is supposed to happen on a component that is a grandchild of where the rate type is set. But as I said, the props value does come through, it's just not updating dynamically, or re-rendering upon change.

import React, { Component } from 'react';
import {Form} from 'react-bootstrap';
import styled from 'styled-components';
import { config } from '../../Config/Constants';
import debounce from 'lodash.debounce';

const API_URL = config.url.API_URL;

const Div = styled.div`
    color: black;
`

class Breakdown extends Component {
    constructor(props) {
        super(props);

        this.state = {
            employee_type: "Choose",
            employee_name: "Choose",
            rate: 0,
            cost: 0,
            hours1: 0,
            hours2: 0,
            hours3: 0,
            total_hours: 0,
            total_costs: 0,
            total_bill: 0,
            margin: 0,

            // Cost Chart
            employeeTable: [
                { name: "Choose", cost: 0, type:"Choose"},
                { name: "Adam N", cost: 95.53, type: "Executive" },
                { name: "Amber H", cost: 50.33, type: "Senior" },
                { name: "Denise M", cost: 28.34, type: "Coordinator" }
            ],

            // Rate Charts
            rateChartNonProfit: [
                { type: "Choose", rate: 0 },
                { type: "Executive", rate: 300 },
                { type: "Senior", rate: 250 },
                { type: "Mid-Level", rate: 200 },
                { type: "Associate", rate: 150 },
                { type: "Coordinator", rate: 150 }
            ], 
            rateChartForProfit: [
                { type: "Choose", rate: 0 },
                { type: "Executive", rate: 400 },
                { type: "Senior", rate: 275 },
                { type: "Mid-Level", rate: 225 },
                { type: "Associate", rate: 175 },
                { type: "Coordinator", rate: 175 }
            ], 
            rateChartExisting: [
                { type: "Choose", rate: 0 },
                { type: "Executive", rate: 400 },
                { type: "Senior", rate: 275 },
                { type: "Mid-Level", rate: 225 },
                { type: "Associate", rate: 175 },
                { type: "Coordinator", rate: 175 }
            ]


            
        }
        

    }

    componentDidMount() {
        this.getBreakdownData(this.props.breakdownId);
    }

    getBreakdownData(breakdownId) {
        fetch(API_URL + `/billingcalculator/${breakdownId}`)
            .then((res) => {
                if (!res.ok) {
                    throw new Error()
                }
                return res.json()
            })
            .then((result) => {
                this.setState({ ...result[0], });
            })
            .catch((error) => {
                console.log(error);
            })
            .then(this.updateRate());
    }

    selectType = (e) => {
        this.setState({ employee_type: e.target.value },
        () => this.updateRate()
        )
    }

    updateRate() {
        let rateType = this.props.rateType;
        if (rateType === "non-profit") {
            const index = this.state.rateChartNonProfit.findIndex(type => type.type === this.state.employee_type);
            this.setState({ rate: this.state.rateChartNonProfit[index].rate },
            () => this.updateTotals());
        } else if (rateType === "existing") {
            const index = this.state.rateChartExisting.findIndex(type => type.type === this.state.employee_type);
            this.setState({ rate: this.state.rateChartExisting[index].rate },
            () => this.updateTotals());
        } else {
            const index = this.state.rateChartForProfit.findIndex(type => type.type === this.state.employee_type);
            this.setState({ rate: this.state.rateChartForProfit[index].rate },
            () => this.updateTotals());
        } 
    }

    

    render() {
        return (
        

            <tr key={this.props.breakdownId}>
                <td>
                    <select name="employee_type" value={this.state.employee_type} onChange={this.selectType}>
                        <option value="Choose">Choose</option>
                        <option value="Executive">Executive</option>
                        <option value="Senior">Senior</option>
                        <option value="Mid-Level">Mid-Level</option>
                        <option value="Associate">Associate</option>
                        <option value="Coordinator">Coordinator</option>
                    </select>
                </td>
                <td>
                    <select name="employee_name" value={this.state.employee_name} onChange={this.selectEmployee}>
                        <option value="Choose">Choose</option>
                        <option value="Adam N">Adam N</option>
                        <option value="Amber H">AmberH</option>
                        <option value="Denise M">Denise M</option>
                    </select>
                </td>
                <td>
                    {this.state.rate}
                </td>
                <td>
                    {this.state.cost}
                </td>
                <td>
                    <Form.Control
                        size="sm"
                        type="text"
                        value={this.state.hours1}
                        onChange={this.handleChange}
                        name="hours1"
                    />
                </td>
                <td>
                    <Form.Control
                        size="sm"
                        type="text"
                        value={this.state.hours2}
                        onChange={this.handleChange}
                        name="hours2"
                    />
                </td>
                <td>
                    <Form.Control
                        size="sm"
                        type="text"
                        value={this.state.hours3}
                        onChange={this.handleChange}
                        name="hours3"
                    />
                </td>
                
                <td>
                    {this.state.total_hours}
                </td>
            </tr>        
        )
    }
}

export default Breakdown;

Upvotes: 3

Views: 101

Answers (1)

kingofsevens
kingofsevens

Reputation: 540

Since you mentioned this:

when I change the rate type on a project, the state does in fact update to the correct type, and I can then select rates, and the numbers shown are correct.

I assume everything works okay because from the code you shared I cannot understand how it is triggered. And I think you need below method to track the change.

componentDidUpdate(prevProps, prevState) {
  // this compares the previous props to the current and triggers anything on change
  if (prevProps.rateType !== this.props.rateType) {
    // write logic here where you change the employee and/or update the other states
  }
}

Upvotes: 2

Related Questions