Search code examples
reactjsecmascript-6use-effectuse-state

useState not forcing re-render of react component


I have a component which a prop value which is an object, one of the properties of value is aliases which is an array of string. I have an add alias button which should add an alias to the object. I am displaying all aliases with .map in the component, but when I add an alias the component does not re-render. I can see the state updating properly with react dev-tools in the browser, but the component does not re-render the updated list. What am I doing wrong?

import Accordion from "@components/common/Accordion"
import Alias from "./value-form/Alias"

const ValueItem = props => {
    const { value } = props
     
    /** EXAMPLE VALUE 

                   "id": 1,
                "name": "Primary Descriptor",
                "programmaticName": "Primary_Descriptor",
                "fileTypeDetailId": 9,
                "fileType": "File Type no. 9",
                "standardValue": "Outgoing",
                "isActive": true,
                "aliases": ["Alias 1", "Alias 2", "Alias 3"]
    */


    const dispatch = useDispatch()


    const [formValue, setFormValue] = useState(value)
    const [formAliases, setFormAliases ] = useState(value.aliases)

    const addAlias = () => {
        const updatedFormValue = formValue;
        updatedFormValue.aliases.push("");
        setFormValue(updatedFormValue)
        setFormAliases(updatedFormValue.aliases)
    }



    return (
        <Accordion
            key={value.id}
            title={value.name} />
            }
        >
            <div className={styles.valueFormContainer}>

                {formAliases.map((alias) => {
                    return ({alias})
                }
                )}
                <Button handleChange={() => { addAlias()}} buttonLabel="+ Add Alias" buttonTypes={["orange"]} />
            </div>
        </Accordion>)
}

export default ValueItem

Solution

  • Your problem is right here

     const addAlias = () => {
        const updatedFormValue = formValue;
        updatedFormValue.aliases.push("");
        setFormValue(updatedFormValue)
        setFormAliases(updatedFormValue.aliases)
    }
    

    you are mutating the exists state.

    https://reactjs.org/docs/hooks-state.html

    in your case i'd use

    setFormValue(prevState=>[...prevState,aliases:[...prevState.aliases,""])