Перерисовка только обновленных элементов в реагирующей форме - PullRequest
0 голосов
/ 21 октября 2019

Я хочу получить динамически построенную форму с контролируемыми компонентами, которые хорошо масштабируются. Проблема, с которой я сталкиваюсь, заключается в том, что при обновлении состояния происходит повторная визуализация всей формы (или что-то дорогое), что вызывает отставание эпического типа.

// Generate some example fields
let defaultFields = {};
for(let n=0; n<1000; n++){
    defaultFields[n.toString()] = {'id':n.toString(), 'value':'','label':'Field '+n}
}
const [valuesById, setValuesById] = useState(defaultFields);

const updateValueCallback = React.useCallback((e)=>{
    e.preventDefault();
    e.persist();
    setValuesById(prevValuesById => {
        let fieldId = e.target.id;
        return {...prevValuesById,
            [fieldId]:{
                'id':fieldId,
                'value':e.target.value,
                'label':'Field '+fieldId
        }};
    });
});
return <div>
    { Object.entries(valuesById).map(([id,formField]) => {
        return <p key={formField.id}>
            <label>{formField.label}
                <SingleLineStringInput isRequired={false} value={formField.value} onChangeCallback={updateValueCallback} id={formField.id} name={'name_'+formField.id} />
            </label>
        </p>
    })
    }
</div>;

Если реквизиты не меняются для 999 изполя, то почему они перерисовывают? Или что на самом деле происходит здесь (поля на самом деле не мигают в инструменте отладки, а родительские)? Мне действительно нужна помощь, чтобы лучше понять это, и исправление, которое не слишком сильно отличается от того, что я сделал, поскольку мы построили большое количество логики поверх этой базовой структуры и только сейчас поняли, что это не масштабирование.

SingleLineInput:

const SingleLineStringInput = React.memo(({name, id, value, onChangeCallback}) => {
    console.log("UPDATING "+id);
    return <input className={'input ' + inputClasses.join(' ')} name={name} id={id} type="text"
                  value={(value === null) ? '' : value}
                  onChange={onChangeCallback} />
});

1 Ответ

1 голос
/ 22 октября 2019

Хорошо, я постараюсь помочь, у вас все хорошо, используя memo и useCallback, но вы не передаете массив зависимостей в useCallback , так как ваш обратный вызов будет одинаковым для каждого рендера, вы можете передатьпустой массив, так что он будет одинаковой функцией при каждом рендеринге. Вы можете сделать это следующим образом:

const updateValueCallback = React.useCallback((e)=>{
e.preventDefault();
e.persist();
setValuesById(prevValuesById => {
    let fieldId = e.target.id;
    return {...prevValuesById,
        [fieldId]:{
            'id':fieldId,
            'value':e.target.value,
            'label':'Field '+fieldId
    }};
});
}, []); // dependencies array

Теперь, если вы измените значение поля, оно будет перерисовано

Песочница , чтобы показать вам, как это делается

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...