传递整个对象时是否可以避免重新渲染所有输入?

Can re-rendering of all inputs be avoided when passing a whole object?

我有很多不同的接口,具有许多属性,例如

interface IEntity1 {
    a: string
    b: number
    c: string
    ....
}

当我想编辑对象(即创建修改后的副本)时,我可以这样做

function Editor(props: {entity: IEntity1, setEntity(e: IEntity1) => void}) {
    const {entity, setEntity} = props;
    const [a, setA] = useState(entity.a);
    const [b, setB] = useState(entity.a);
    ....
    function handleOk() {
       setEntity({a, b, c, ...});
    }

    return <div>
       <input value={a} onChange={e => setA(e.target.value}/>
       <input value={''+b} onChange={e => setB(+e.target.value}/>
       <input value={c} onChange={e => setC(e.target.value}/>
       ...
       <button onClick={handleOk}>OK</button>
    </div>;
}

这工作正常,但重复性很强。所以我创建了一个 "universal" 组件,它可以处理数字、字符串和其他输入。使用它,我可以像

这样循环处理所有字段
{fieldNames.map(f => <Edit value={entity[f]}
                       onChange={newValue => setEntity({...entity}, {[f]: newValue})}/>)}

我可以轻松生成所有需要的元数据(为简单起见,以上只是 fieldNames: string[])。

我可以做得更好
{fieldsMetadata.map(f => <Edit2 entity={entity} field={f}/>)}

其中 Edit2 是一个 "smarter" 组件。 令我困扰的是所有我的编辑都会在任何更改时重新呈现。这可能是过早的优化,但考虑到我想在很多页面上多次使用这个组件,这可能是一个有效的问题。

所以我想问是否有可能编写这样一个组件而不用每次都重新渲染,或者是否有一些与性能相关的东西我错过了?

你的组件重新渲染的问题是因为在传递内联箭头函数时,它会在每次渲染时再次创建

一旦你避免了它,你可以使用 React.memo 或 PureComponent 来实现每个 Edit 组件,这取决于你是将它实现为功能组件还是 class

const onChange= useCallback((name, value) => {
     setEntity(prev => ({...prev, [name]: value}));
}, []);
 ...
{fieldNames.map(f => <Edit name={f} value={entity[f]}
                       onChange={onChange}/>)}

编辑组件就像

const Edit = (props) => {
    const {value, name, setEntity} = props;
    const handleChange = (e) => {
         const newValue = e.target.value;
         onChange(name, newValue);
    }

    return <input value={value} name={name} onChange={handleChange} />

}

export default React.memo(Edit)

P.S 确保使用 setEntity

正确合并状态