当多个组件使用复杂对象的一部分来源时,redux如何工作
我有一个对象(这是一个属性数组,因为它是动态的,我不能将它拆分成多个属性)这样的:当多个组件使用复杂对象的一部分来源时,redux如何工作
[
{type: list, elements: []}
{type: map, elements: []}
{type: wheelList, elements: []}
{type: chart, elements: []}
{type: dyna, elements: []}
...
]
在一个组件,我得到它的存储和访问它想:
this.props.allElements
然后,每它我呈现不同的组件(伪代码):
foreach (el in this.props.allElements) {
if (el == list) {
return <ListComponent elements={el.elements}>
}
if (el == map) {
return <MapComponent elements={el.elements}>
}
...
}
这样每个组件只获取感兴趣的元素。
我的问题是关于性能和优化。
我的方法有什么好处吗?
我遇到一些性能问题,所以请检查我的组织
是否有问题,如果可以改进,则需要咨询。
我有一些频繁更新,有时地图可以每秒更新一次。
因此,如果我只更新地图元素并将其传递给动作以进行更新,则所有这些组件都将再次运行渲染或仅显示地图。
UPDATE
但更新map
元素我需要得到整个这个object
从store
在action update only map
元素,然后整个更新的对象传递给reducer
。
所以只有地图被改变别人不是。
反应/ redux是否足够智能以仅更新数据发生更改的组件(在我的情况下为地图)。
操作:
export function getScreenElements() : Action {
return function(dispatch) {
// get data from server here
// and do some calculations here
dispatch({
type: 'ELEMENTS_RECEIVED',
allElements: data
});
减速机:
export default function (state:State = initialState, action:Action): State {
if (action.type === 'ELEMENTS_RECEIVED') {
return {
...state,
allElements: action.allElements,
};
在大部件:
const mapStateToProps = state => ({
allElements: state.main.allElements
...
class Main extends Component {
...
componentDidMount() {
// here I actually make a call to get data
}
...
render() {
return (
// Here is the big code
// Loop over props.allElements
// and render it in different way based on data inside each element
)
}
数据例如:
[
{
"type": "list",
"count": 99,
"elements": [
{
"id": 1,
"name": "test"
},
{
"id": 2,
"name": "test1"
}
]
},
{
"type": "map",
"count": 99,
"elements": [
{
"id": 3,
"name": "test"
},
{
"id": 4,
"name": "test1"
}
]
},
{
"type": "list",
"count": 99,
"elements": [
{
"id": 5,
"name": "test"
},
{
"id": 6,
"name": "test1"
}
]
},
{
"type": "list",
"count": 99,
"elements": [
{
"id": 7,
"name": "test"
},
{
"id": 8,
"name": "test1"
}
]
}
]
您可以在thunk
action
中执行循环,并将数据拆分为单独的reducers
。
你的行动可能看起来像这样:
// action thunk
export function getScreenElements() {
return function (dispatch) {
// get data from server here
const dataFromServer = fetch('url');
// do your looping here and dispatch each data acording to its type
dataFromServer.map(obj => {
switch (obj.type) {
case 'list':
dispatch({
type: 'LIST_RECEIVED',
listElements: obj
});
case 'map':
dispatch({
type: 'MAP_RECEIVED',
mapElements: obj
});
// ....
}
});
}
}
你单独减速可能是这个样子:
// map reducer
export default function map(state = initialState, action) {
if (action.type === 'MAP_RECEIVED') {
return {
...state,
mapElements: action.mapElements,
}
}
}
// list reducer
export default function list(state = initialState, action) {
if (action.type === 'LIST_RECEIVED') {
return {
...state,
listElements: action.listElements,
}
}
}
然后你就可以使它像这样:
// inside your component render mehtod
render(){
const { list, map } = this.props; // redux data passed as props from the seperate reducers
return (
<div>
<ListComponent elements={list}>
<MapComponent elements={map}>
</div>
);
}
编辑
作为随访到您的评论:
如果我把ALLDATA于母公司并通过allData.xyz到组件中呈现 当任何数据变化父也将重新描绘,因为它的道具是 改变
那么,父母被重新渲染没有任何错误。 component
的render
方法运行并不意味着它会重新渲染到实体DOM
,它将更新或覆盖虚拟对象DOM
然后将通过Reconciliation and The Diffing Algorithm检查物理和虚拟DOM
之间的差异以确定何时,如何以及在哪里应该更新物理DOM
。
它可以只更新DOM
元素的某些属性而不重新渲染它们,React Only Updates What’s Necessary。
也有React.PureComponent的选项,但我坚决反对你的情况。
在您的数据示例中,有多个具有相同类型的项目(例如:列表)。
Redux不推荐这种嵌套对象,因为您将无法优化渲染或优化数据失效。
之一以优化的方式就是击败你的数据,以便看起来像这样:
{
isFetching: false,
didInvalidate: false,
data: [
{ type: 'list', id: 1, name: 'test' },
{ type: 'list', id: 2, name: 'test1' },
{ type: 'map', id: 3, name: 'test' },
{ type: 'map', id: 4, name: 'test1' },
{ type: 'list', id: 5, name: 'test' },
{ type: 'list', id: 6, name: 'test1' },
{ type: 'list', id: 7, name: 'test' },
{ type: 'list', id: 8, name: 'test1' },
]
}
app.js
class App extends React.Component {
render() {
return (
<div>
<ListComponent />
<MapComponent />
</div>
);
}
}
selectors.js
使用reselect
图书馆为了避免无用的重投。
此选择器是共享的,因为您可以将它用于ListComponent
,MapComponent
和所有其他组件以查找与您的类型相对应的项目。
import { createSelector } from 'reselect';
export const typeElementsSelector = createSelector(
state => state.allElements.data,
(allElements, props) => allElements.find(element => element.type === props.type),
);
ListComponent。js
这里的诀窍是只传递元素id
并让孩子检查何时重置。
注意ListComponent
将重新呈现仅且仅当没有在listElements
值进行任何修改。 实例:
- 现在有一种类型“列表”的一个新的项
- 有被修改类型“列表”
- 一个当前的“列表”项中的一个被移除的项
代码:
import React from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { typeElementsSelector } from './selectors';
class ListComponent extends React.Component {
render() {
if (!this.props.listElements.length) return (<div>Empty</div>);
return (
<div>
<h2>{this.props.listElements.length} list elements</h2>
<div>
{this.props.listElements.map(element => (
<ListComponentItem key={`list-${element.id}`} id={element.id} />
))}
</div>
</div>
);
}
}
const mapStateToProps = (reducers, props) => ({
listElements: typeElementsSelector(reducers, props),
});
export default connect(mapStateToProps)(ListComponent);
ListComponentItem.js
您现在可以显示任何你想要的东西。 该组件将只且仅当在减速机这项已被修改
import React from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
class ListComponentItem extends React.Component {
render() {
return <div>{this.props.name}</div>
}
}
const elementSelector = createSelector(
state => state.allElements.data,
(allElements, props) => allElements.find(element => element.id === props.id),
);
const mapStateToProps = (reducers, props) => ({
element: elementSelector(reducers, props),
});
export default connect(mapStateToProps)(ListComponentItem);
的另一种方法是创建为每种类型的一个减速器,并使用相同的逻辑如上重新呈现。
{
listElements: {
isFetching: false,
didInvalidate: false,
data: [
{ id: 1, name: 'test' },
{ id: 2, name: 'test1' },
{ id: 5, name: 'test' },
{ id: 6, name: 'test1' },
{ id: 7, name: 'test' },
{ id: 8, name: 'test1' },
]
},
mapElements: {
isFetching: false,
didInvalidate: false,
data: [
{ id: 3, name: 'test' },
{ id: 4, name: 'test1' },
]
},
}
请记住,您的API可能会以某种方式向您发送格式化的数据,但您可以根据需要重新格式化它们。
一个有趣的文章谈论这种优化:https://medium.com/dailyjs/react-is-slow-react-is-fast-optimizing-react-apps-in-practice-394176a11fba
如果你想走得更远终极版与数据标准化的最佳实践:https://github.com/paularmstrong/normalizr
希望它能帮助。
为什么你不把它分裂成不同的减速器呢? –
我真的会从中受益吗?这是我从服务器获得的对象,它非常动态。这就是为什么我要求解释如何应对这种情况。它会只更新一个还是全部? – 1110
好吧,我认为在'render'中做这件事不太可取,那么在一个'thunk'(动作创建器)内循环并将每个'type'分配给不同的'reducer'是不太可取的。 –