Search code examples
javascriptnode.jsreactjsreduxvirtual-dom

React rerendering - misunderstanding


I thought React was just reloading the things I needed - in my case it looks different or I've done something wrong.

I have table of employees. For each employee in single day I can set start and end of work time. Like this:

const ScheduleRow = React.memo((props) => {
    return (
        <tr>
            // number of row - doesn't matter
            <th className="text-center">{ props.no }</th>
            { ["2020-01-01", "2020-01-02", "2020-01-03", "2020-01-04" /* etc */ ].map(
                date => { return (
                    <ScheduleCell date={ date } employee_id={ props.employee_id }/>
                )}) }
        </tr>
    )
})

const ScheduleCell = React.memo((props) => {
    const dispatch = useDispatch()

    let schedule_id = `${props.employee_id}:${props.date}`
    const schedule = useSelector(state => state.schedules)[schedule_id] || null

    /* some code here - not changing state */

    console.log(props.date)

    return (
        <td>
            <Form.Control type="text" value={schedule?.begin}
                onChange={(e) => dispatch({
                    type: "EDIT_SCHEDULE",
                    schedule_id: schedule_id,
                    property: "begin",
                    value: e.target.value
                })}/>
            <Form.Control type="text" value={schedule?.cease}
                onChange={(e) => dispatch({
                    type: "EDIT_SCHEDULE",
                    schedule_id: schedule_id,
                    property: "cease",
                    value: e.target.value
                })}/>
        </td>
    )
});

You can see that I have console.log() in ScheduleCell before return which prints date of day which is editing. I belive that when I change cell ( e.g date "2020-01-02" ) I should see only "2020-01-02" in console. But I see every dates from array in ScheduleRow it's mean that React modify every cells even if I changed only one cell.

What is wrong with my reasoning and how can improve it to reload only editing cell ?


Solution

  • Make sure you add a proper key prop to your <ScheduleCell/> elements. Without this, React won't correlate that the same component instance should be reused on re-render. Same goes for whatever renders <ScheduleRow/>.

    const ScheduleRow = React.memo((props) => {
        return (
            <tr>
                <th className="text-center">{ props.no }</th> // number of row - doesn't matter
                { ["2020-01-01", "2020-01-02", "2020-01-03", "2020-01-04" /* etc */ ].map(date => { return (
                    <ScheduleCell key={ date } date={ date } employee_id={ props.employee_id }/>
                )}) }
            </tr>
        )
    })
    

    React.memo only memoizes the output within the context of a component instance if the props are the same as the last time that instance rendered. For more on how this works, read up on React's Reconciliation.