传递整个对象时是否可以避免重新渲染所有输入?
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
正确合并状态
我有很多不同的接口,具有许多属性,例如
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
正确合并状态