Nested state with different many keys

Posted on

Problem

I have a nested state which is needed to set its state by a key’s value:

state = {
    income_source: {
        type: 'text', label_name: 'Income Source', value: '', helper: 'dropdown',
    },
    employment_status: {
        type: 'text', label_name: 'Employment Status', value: '', helper: 'dropdown',
    },

...

I’m getting a huge list from a get_financial_assessment object and the code becomes messy when I tried to setState in componentDidMount():

async componentDidMount() {
    let { get_financial_assessment } = await DAO.getFinancialAssessment()
    if( get_financial_assessment ) {
        const {
            account_turnover,
            cfd_score,
            education_level,
            employment_industry,
            employment_status,
            estimated_worth,
            financial_information_score,
            income_source,
            net_income,
            occupation,
            source_of_wealth,
            total_score,
            trading_score,
        } = get_financial_assessment;

        this.setState(prevState => ({
            anticipated_account_turnover: {...prevState.anticipated_account_turnover, value: account_turnover},
            occupation: {...prevState.occupation, value: cfd_score},
            level_of_education: {...prevState.level_of_education, value: education_level},
            source_of_wealth: {...prevState.source_of_wealth, value: employment_industry},
            net_annual_income: {...prevState.net_annual_income, value: employment_status},
            estimated_net_worth: {...prevState.estimated_net_worth, value: estimated_worth},
            source_of_wealth: {...prevState.source_of_wealth, value: financial_information_score},
        }));
    } else {
        console.log('nope');
    }
}

Any better way? One possible approach might be, once we get the data, we can make an object and setState the object to the state. Would it be the best possible answer?

Solution

First things first, I am against using different names in things that are inherently the same. If you do not have any other option, you could the data coming from the DAO as soon as they are fetched from the server.

If that is not an option, since this code is indeed messy, I would move this logic into a function while indicating the mapping from one state to the other (this is similar to what Redux does with mapStateToProps).

const mapFinancialAssesmentToState = (fa, state) => {
  const mapping = {
    anticipated_account_turnover: fa.account_turnover,
    occupation: fa.cfd_score
    //...
  };
  const nextState = {};
  Object.keys(mapping).forEach(key => {
    nextState[key] = { ...state[key], value: mapping[key] };
  })
  return nextState;
}

async componentDidMount() {
  let { get_financial_assessment } = await DAO.getFinancialAssessment();
  if (get_financial_assessment) {
      this.setState(mapFinancialAssesmentToState(get_financial_assessment, this.state))
  } else {
    console.log('nope');
  }
}

Leave a Reply

Your email address will not be published. Required fields are marked *