<CommentItem likeComment={() => this.likeComment(user.id)} />
这个问题会导致每次父组件render方法被调用时,一个新的函数被创建,已将其传入likeComment。这会有一个改变每个子组件props的副作用,它将会造成他们全部重新渲染,即使数据本身没有发生变化
子组件的likeComment属性将总是有相同的引用,这样就不会造成不必要的重新渲染
// 方法1
import { useCallback } from 'react';
const List = ()=> {
const comment = (id) => { doing something}
const likeComment = useCallback(()=> { comment(id) }, [id]);
// 这样自组建就不会从新渲染
return list.map (
v => <CommentItem onClick={likeComment(v.id)} >)
}
然后再子组件中创建一个引用了传入属性的类方法:
//方法2
<CommentItem likeComment={this.likeComment} userID={user.id} />
class CommentItem extends PureComponent {
...
handleLike() {
this.props.likeComment(this.props.userID)
}
...
}
不要在render方法里派生数据
每次组件重新渲染时topTen都将有一个新的引用,即使posts没有改变并且派生数据也是相同的。这将造成列表不必要的重新渲染。
render() {
const { posts } = this.props
const topTen = posts.sort((a, b) => b.likes - a.likes).slice(0, 9)
return //...
}
使用派生方法解决
static getDerivedStateFromProps(nextProps, state) {
if (
props.list !== state.prevPropsList ||
state.prevFilterText !== state.filterText
)
}
管理派生 state 本来就很复杂,而且这种复杂度是随着需要管理的属性变得越来越庞大。比如,如果我们想在组件 state 里添加第二个派生 state,那就需要写两份跟踪变化的逻辑。
import memoize from "memoize-one";
class Example extends Component {
// state 只需要保存当前的 filter 值:
state = { filterText: "" };
// 在 list 或者 filter 变化时,重新运行 filter:
filter = memoize(
(list, filterText) => list.filter(item => item.text.includes(filterText))
);
handleChange = event => {
this.setState({ filterText: event.target.value });
};
render() {
// 计算最新的过滤后的 list。
// 如果和上次 render 参数一样,`memoize-one` 会重复使用上一次的值。
const filteredList = this.filter(this.props.list, this.state.filterText);
return (
<Fragment>
<input onChange={this.handleChange} value={this.state.filterText} />
<ul>{filteredList.map(item => <li key={item.id}>{item.text}</li>)}</ul>
</Fragment>
);
}
}
在使用 memoization 时,请记住这些约束:
- 大部分情况下, 每个组件内部都要引入 memoized 方法,已免实例之间相互影响。
- 一般情况下,我们会限制 memoization 帮助函数的缓存空间,以免内存泄漏。(上面的例子中,使用 memoize-one 只缓存最后一次的参数和结果)。
- 如果每次父组件都传入新的 props.list ,那本文提到的问题都不会遇到。在大多数情况下,这种方式是可取的。
如果你正在使用Redux,可以考虑使用reselect来创建”selectors”来组合和缓存派生数据。
One Reply to “react 注意事项”