React + Redux에서 중첩된 컴포넌트의 소품 업데이트를 최적화하는 방법
코드 예: https://github.com/d6u/example-redux-update-nested-props/blob/master/one-connect/index.js
라이브 데모 보기:http://d6u.github.io/example-redux-update-nested-props/one-connect.html
네스트된 컴포넌트의 소품 업데이트를 최적화하려면 어떻게 해야 합니까?
위의 컴포넌트인 Repo와 RepoList가 있습니다.첫 번째 repo(14호선)의 태그를 갱신하고 싶습니다.그래서 제가 파견을 했습니다.UPDATE_TAG
★★★★★★★★★★★★★★★★★★★를 실장하기 전에shouldComponentUpdate
에는 약 은 「200밀리초」를 「200밀리초」로 것으로, 시간을 하고 있기 때문입니다.이것은 많은 시간을 소비하고 있기 때문입니다.<Repo/>
변경되지 않았습니다.
후 ★★★shouldComponentUpdate
30밀리초리액트.js의 17밀리초.이것은 훨씬 더 좋지만 Chrome 개발 콘솔의 타임라인 뷰에는 여전히 jank frame(16.6ms보다 긴)이 표시됩니다.
내용이 가정해 보세요.<Repo/>
60fps로 하다
궁금한 점은 네스트된 컴포넌트의 소품 업데이트를 위해 콘텐츠를 보다 효율적이고 표준적인 방법으로 업데이트 할 수 있을까요?아직 Redux를 사용할 수 있습니까?
는 모든 것을 을 얻었다.tags
을 사용법 같은 거
// inside reducer when handling UPDATE_TAG action
// repos[0].tags of state is already replaced with a Rx.BehaviorSubject
get('repos[0].tags', state).onNext([{
id: 213,
text: 'Node.js'
}]);
그런 다음 https://github.com/jayphelps/react-observable-subscribe을 사용하여 Repo 컴포넌트 내의 값을 구독합니다.이거 잘 됐다.React.js의 개발 빌드에서도 디스패치 비용은 5ms에 불과합니다.근데 이게 레독스의 안티패턴인 것 같아요
업데이트 1
Dan Abramov의 답변에 있는 권장 사항에 따라 상태를 정상화하고 연결 컴포넌트를 업데이트했습니다.
새로운 상태 셰이프는 다음과 같습니다.
{
repoIds: ['1', '2', '3', ...],
reposById: {
'1': {...},
'2': {...}
}
}
는 ㅇㅇㅇㅇㅇㅇㅇㅇ다를 넣었습니다.console.time
위에 ReactDOM.render
초기 렌더링 시간을 설정합니다.
다만, 퍼포먼스는 이전보다 저하하고 있습니다(초기 렌더링과 갱신 모두).(출처: https://github.com/d6u/example-redux-update-nested-props/blob/master/repo-connect/index.js, 라이브 데모: http://d6u.github.io/example-redux-update-nested-props/repo-connect.html)
// With dev build
INITIAL: 520.208ms
DISPATCH: 40.782ms
// With prod build
INITIAL: 138.872ms
DISPATCH: 23.054ms
제 생각에는 매회 접속하는 것 같아요.<Repo/>
버헤드가가많많많많
업데이트 2
답변을 는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★connect
의 »mapStateToProps
인수 대신 함수를 반환합니다.댄의 답변을 확인하실 수 있습니다.데모도 업데이트했습니다.
아래는 내 컴퓨터가 훨씬 더 성능이 좋다.또, 재미삼아 말씀드린 리듀서 어프로치(소스, 데모)의 부작용도 추가했습니다(진지하게 사용하지 말아 주세요.실험용입니다).
// in prod build (not average, very small sample)
// one connect at root
INITIAL: 83.789ms
DISPATCH: 17.332ms
// connect at every <Repo/>
INITIAL: 126.557ms
DISPATCH: 22.573ms
// connect at every <Repo/> with memorization
INITIAL: 125.115ms
DISPATCH: 9.784ms
// observables + side effect in reducers (don't use!)
INITIAL: 163.923ms
DISPATCH: 4.383ms
업데이트 3
"메모리와 함께 연결"을 기반으로 한 리액트 가상화 예제를 방금 추가했습니다.
INITIAL: 31.878ms
DISPATCH: 4.549ms
에 있는지 모르겠다const App = connect((state) => state)(RepoList)
신이이다
React Redux 문서의 대응하는 예에는 다음과 같은 알림이 있습니다.
이러지 마!TodoApp은 모든 작업 후 재렌더되므로 성능 최적화가 중단됩니다.뷰 계층 내의 여러 컴포넌트에 대해 보다 세밀한 connect()를 설정하는 것이 좋습니다.각 컴포넌트는 관련된 상태의 슬라이스만 듣습니다.
이 패턴을 사용하는 것은 권장하지 않습니다. 각 접속은 「」입니다.<Repo>
으로는 '자신의 ', '자신의 를 읽는다', '자신의 데이터를 읽는다', '의 데이터를 읽습니다.mapStateToProps
. "tree-view" 예시는 그 방법을 보여줍니다.
상태 모양을 더 정규화하면(당장은 모두 중첩됨) 분리할 수 있습니다.repoIds
부에서reposById
, 그리고 음 네, 다 직, 오, and, ,, have, 그, your, ,RepoList
re-render if 의 여부를 재검증명하다repoIds
바꾸다.다 이 방법은 개별 리포지토리에 영향을 주지 않을 것이며, 법 별 을 향 을 록 지 경 은 니 this 향 에 꾸 영ual repos the변않Repo
재취득이 됩니다.이 풀 요청을 통해 어떻게 작동하는지 알 수 있습니다.「실제」의 예에서는, 정규화된 데이터를 처리하는 리듀서를 쓰는 방법을 나타내고 있습니다.
트리를 정규화함으로써 제공되는 퍼포먼스를 진정으로 활용하려면 이 풀 요구와 동일하게 수행하여 다음 명령을 전달해야 합니다.mapStateToProps()
★★★★★★★★★로connect()
:
const makeMapStateToProps = (initialState, initialOwnProps) => {
const { id } = initialOwnProps
const mapStateToProps = (state) => {
const { todos } = state
const todo = todos.byId[id]
return {
todo
}
}
return mapStateToProps
}
export default connect(
makeMapStateToProps
)(TodoItem)
이것이 중요한 이유는 ID는 절대 변하지 않는다는 것을 알기 때문입니다.「」를 사용합니다.ownProps
이치노외부 소품이 변경될 때마다 내부 소품을 재계산해야 합니다., 「」를 사용하고 .initialOwnProps
이 패널티는 1회만 사용되므로 발생하지 않습니다.
이 예제의 고속 버전은 다음과 같습니다.
import React from 'react';
import ReactDOM from 'react-dom';
import {createStore} from 'redux';
import {Provider, connect} from 'react-redux';
import set from 'lodash/fp/set';
import pipe from 'lodash/fp/pipe';
import groupBy from 'lodash/fp/groupBy';
import mapValues from 'lodash/fp/mapValues';
const UPDATE_TAG = 'UPDATE_TAG';
const reposById = pipe(
groupBy('id'),
mapValues(repos => repos[0])
)(require('json!../repos.json'));
const repoIds = Object.keys(reposById);
const store = createStore((state = {repoIds, reposById}, action) => {
switch (action.type) {
case UPDATE_TAG:
return set('reposById.1.tags[0]', {id: 213, text: 'Node.js'}, state);
default:
return state;
}
});
const Repo = ({repo}) => {
const [authorName, repoName] = repo.full_name.split('/');
return (
<li className="repo-item">
<div className="repo-full-name">
<span className="repo-name">{repoName}</span>
<span className="repo-author-name"> / {authorName}</span>
</div>
<ol className="repo-tags">
{repo.tags.map((tag) => <li className="repo-tag-item" key={tag.id}>{tag.text}</li>)}
</ol>
<div className="repo-desc">{repo.description}</div>
</li>
);
}
const ConnectedRepo = connect(
(initialState, initialOwnProps) => (state) => ({
repo: state.reposById[initialOwnProps.repoId]
})
)(Repo);
const RepoList = ({repoIds}) => {
return <ol className="repos">{repoIds.map((id) => <ConnectedRepo repoId={id} key={id}/>)}</ol>;
};
const App = connect(
(state) => ({repoIds: state.repoIds})
)(RepoList);
console.time('INITIAL');
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('app')
);
console.timeEnd('INITIAL');
setTimeout(() => {
console.time('DISPATCH');
store.dispatch({
type: UPDATE_TAG
});
console.timeEnd('DISPATCH');
}, 1000);
가 '아예'를 바꾼 에 주의하세요.connect()
ConnectedRepo
을 initialOwnProps
ownProps
리액트 리덕스(Respect Redux)를 사용합니다.
.shouldComponentUpdate()
<Repo>
는 React Redux에서 입니다.connect()
.
이 방법은 테스트에서 이전의 두 가지 방법을 모두 능가합니다.
one-connect.js: 43.272ms
repo-connect.js before changes: 61.781ms
repo-connect.js after changes: 19.954ms
마지막으로, 이렇게 많은 데이터를 표시해야 한다면, 어쨌든 화면에 맞지 않습니다.이 경우 가상화된 테이블을 사용하여 실제로 표시할 때의 성능 오버헤드 없이 수천 개의 행을 렌더링할 수 있습니다.
나는 모든 태그를 관찰 가능한 내부 환원기로 교체함으로써 해결책을 얻었다.
부작용이 있다면 레독스 환원제가 아닙니다.동작할 수도 있지만 혼란을 피하기 위해 이와 같은 코드를 Redx 외부에 배치하는 것이 좋습니다., '레덕스 리덕터'를 할 수 .onNext
토픽에 대해서.
언급URL : https://stackoverflow.com/questions/37264415/how-to-optimize-small-updates-to-props-of-nested-component-in-react-redux
'prosource' 카테고리의 다른 글
ESLint with React에서 "no-used-vars" 오류가 발생함 (0) | 2023.03.14 |
---|---|
React.Children.map 재귀적으로? (0) | 2023.03.14 |
Reactjs를 사용하여 스크롤 위치 가져오기 (0) | 2023.03.14 |
Angular UI-Router "레이아웃" 상태를 만드는 방법 (0) | 2023.03.14 |
JDBC 문을 통해 "DDL 실행 오류 "변경 테이블 이벤트 드롭 외부 키 FKg0mkvgsqn8584qoql6a2rxheq" 수정 방법 (0) | 2023.03.09 |