限制 Redux 仅更新受更改影响的组件

Posted

技术标签:

【中文标题】限制 Redux 仅更新受更改影响的组件【英文标题】:Limit Redux to update only components affected by the change 【发布时间】:2016-12-15 22:58:12 【问题描述】:

试图理解 React-Redux,我发现当状态的任何部分发生变化时,我的所有组件都会获得新的 props,这很不寻常。那么这是设计使然还是我做错了什么?

示例应用

class App extends React.Component 

  render()return (
          <div> 
            <Navbar data=this.props.navbar />
            <Content data=this.props.content />
          </div>);
  


select (state) => ( navbar:state.navbar, content:state.content);
export default connect(select)(App);

组件

export const NavbarForm = props => 
  console.log('RENDERING with props--->',props);
  return (<h1>NAV props.data.val</h1>);
;
export const ContentForm = props => 
  console.log('RENDERING CONTENT with props--->',props);
  return (<h1>CONTENT props.data.val</h1>);
;

////////INDEX.js//////

const placeholderReducer = (state=val:0,action)=>
//will update val to current time if action start with test/;
if(action.type.indexOf('TEST/') === 0)return val:Date.now();

return state;


export const rootReducer = combineReducers(
  navbar:placeholderReducer,
  content: (state,action)=>(state || ), //**this will never do a thing.. so content should never updates right !!**
);

const store = createStore(rootReducer, , applyMiddleware(thunk));

render( <Provider store=store> <App /></Provider>, document.getElementById('app')
);
setInterval(()=>  store.dispatch(()=>type:'TEST/BOOM')  ,3000);

好的,在这个应用程序中,我期望导航栏组件将每 3000 毫秒更新一次,而内容组件将永远不会更新,因为它的减速器将始终返回相同的状态。

但我发现每次触发动作时两个组件都会重新渲染,这真的很奇怪。

这是设计使然吗?如果我的应用有 100 多个组件,我应该担心性能吗?

【问题讨论】:

您的应用在性能方面无法很好地扩展,但我会回答您的主要问题。将您的导航栏功能组件转换为基于类的组件并添加生命周期方法componentWillReceiveProps(nextProps) 然后设置您的状态...要了解更多信息,请阅读here @AdegbuyiAdemola 为什么它不会扩展?这不是 redux 文档中提出的结构吗?你能详细说明:)吗?添加生命周期将如何阻止 react-redux 更新道具? 如果存储出现问题,您可能会遇到最大堆栈超出错误。我没有说添加生命周期会阻止 react-redux ......我的意思是,你也应该在 Navbar 上使用它并使 Navbar 成为基于类的组件 请记住,在 React 中 render 并不一定意味着更改 DOM。这意味着运行渲染算法来检查 DOM 是否需要更新。所以render 操作可能是亚毫秒级的。另外,请查看新的React.PureComponent 【参考方案1】:

这完全是设计使然。 React 假设你的整个应用程序默认会从上到下重新渲染,或者如果某个组件执行setState 或类似的操作,至少会重新渲染给定的子树。

因为您只连接了应用程序中最顶层的组件,所以从那里开始的所有内容都是 React 的标准行为。父组件重新渲染,导致其所有子组件重新渲染,导致所有它们的子组件重新渲染,以此类推。

在 React 中提高 UI 性能的核心方法是使用 shouldComponentUpdate 生命周期方法来检查传入的 props,如果组件不需要重新渲染,则返回 false。这将导致 React 跳过重新渲染该组件它的所有后代。 shouldComponentUpdate 中的比较通常使用浅引用相等来完成,这就是“相同的对象引用意味着不更新”这件事变得有用的地方。

在使用 Redux 和 connect 时,您几乎总是会发现自己在 UI 中的许多不同组件上使用 connect。这提供了许多好处。组件可以单独提取它们需要的存储状态片段,而不必将它们全部从根组件中传递下来。此外,connect 为您实现了默认的shouldComponentUpdate并且 对您从mapStateToProps 函数返回的值进行类似的检查。因此,从某种意义上说,在多个组件上使用 connect 往往会给您带来性能方面的“免费胜利”。

进一步阅读该主题:

Redux FAQ: Connecting multiple components React/Redux Links: Performance articles

【讨论】:

【参考方案2】:

是的,这是设计使然。动作已发送。减速机运行。商店订阅者收到通知“商店已更改”。连接的组件是商店订阅者。

通常情况下,您不必担心它,直到您可以真正衡量可以归因于此的性能问题 - 不要过早地优化。

如果您发现它有问题,那么您可以执行以下操作之一:

为你的组件添加一个shouldComponentUpdate 方法,这样他们就可以看到他们收到的道具没有什么不同并且不需要渲染(有很多 Pure Render mixins 和高阶组件可以让这变得简单) 不连接***应用,而是直接连接 Navbar 和 Content 组件。应用程序永远不会重新渲染,但如果商店发生变化,孩子们会。并且 react-redux 自动使用 shouldComponentUpdate 仅重新渲染实际上具有新道具的连接组件。

【讨论】:

我建议再做两件事,使用 Perf 工具来验证优化的需要,并从 React 15.3 开始使用 React.PureComponent(如果适用)

以上是关于限制 Redux 仅更新受更改影响的组件的主要内容,如果未能解决你的问题,请参考以下文章

React,redux 组件不会在路由更改时更新

如何使用 Redux 只更新组件的一个实例?

从 redux 更改状态后如何以及何时调用反应组件方法

React Redux 表更新行

React/Redux:悬停一个组件时,更改所有组件的颜色

React Redux Store 更新,但组件不重新渲染