I am new to React. I have to implement a button that adds few fields(text boxes, select, checkbox) on the page on every click of the button. I have achieved this by referring example http://jsfiddle.net/rpd32h1g/. I have 3 classes 1. Parent class where I have written the logic to populate the subSectionList which defines the components/fields that need to be added on the click of a button. 2. Child component(AddAccount.js) which receives the param subSectionList from the parent and passes it to the array of sub child Account.js. This array is created on click of the button and on each click the array is updated. 3. Sub child component (Account.js) which receives the param subSectionList and iterate it to show the required components. Problem: The sub child Account.js is not being re-rendered if the value of subSectionList is changed in the parent. Below is the code for reference:
Calling below function(findApplicableFields) onChange of field added using the button(this methid exists in parent class).
const findApplicableFields = (questions, questionName, optionName, currentQuestion) => {
const newSubSectionList = questions.map(question => {
if (question.name === questionName) {
return { ...question, children };
}
return { ...question };
});
subSectionList[questionName] = newSubSectionList;
}
Below is the code snippet of the child:
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import Account from './Account';
export default function AddAccount({
buttonText,
type = 'button',
buttonClass,
questions,
checkoutJourney,
handleBlur,
isValid,
question,
onChange,
subSectionList,
...rest
}) {
const [addAccount, setAddAccount] = useState(true);
const [accountArray, setAccountArray] = useState(
checkoutJourney['addAccountArray'] == null ? [] : checkoutJourney['addAccountArray']
);
let i = 0;
const _onClick = e => {
e.preventDefault();
setAddAccount(true);
setAccountArray([
<Account
key={i}
questions={questions}
checkoutJourney={checkoutJourney}
handleBlur={handleBlur}
onChange={onChange}
isValid={isValid}
questionName={question.name}
subSectionList={subSectionList}
{...rest}
/>,
...accountArray
]);
checkoutJourney['addAccountArray'] = accountArray;
checkoutJourney['subSectionList'] = subSectionList;
i++;
};
return (
<>
{addAccount ? accountArray : null}
<div className={buttonClass}>
<button
className="button button--dark button--primary"
type={type}
onClick={e => {
_onClick(e);
}}
>
{buttonText}
</button>
</div>
</>
);
}
AddAccount.propTypes = {
_onClick: PropTypes.func,
type: PropTypes.string,
buttonText: PropTypes.string,
buttonClass: PropTypes.string,
questions: PropTypes.array,
onChange: PropTypes.func,
checkoutJourney: PropTypes.object,
rest: PropTypes.object,
handleBlur: PropTypes.func,
isValid: PropTypes.object,
question: PropTypes.any,
subSectionList: PropTypes.object
};
AddAccount.defaultProps = {
buttonText: '+ Add another account'
};
Below is the code snippet of sub child which needs to be re-rendered:
import React from 'react';
import PropTypes from 'prop-types';
import TextInput from '../TextInput/WS2TextInput';
import Select from '../Select/WS2Select';
import AddressMoreServices from '../AddMoreServices/AddMoreServices';
import Checkbox from '../Checkbox/Checkbox';
const Account = ({ checkoutJourney, handleBlur, isValid, onChange, subSectionList, questionName, ...rest }) => {
return (
<>
{subSectionList[questionName].map((question, i, questions) => {
//The logic to render the field based on type of question
})}
</>
);
}
Account.propTypes = {
questions: PropTypes.array,
onChange: PropTypes.func,
checkoutJourney: PropTypes.object,
rest: PropTypes.object,
handleBlur: PropTypes.func,
isValid: PropTypes.object,
subSectionList: PropTypes.object,
questionName: PropTypes.string
};
export default Account;