prosource

React + Redux에서 중첩된 컴포넌트의 소품 업데이트를 최적화하는 방법

probook 2023. 3. 14. 21:43
반응형

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/>변경되지 않았습니다.

후 ★★★shouldComponentUpdate30밀리초리액트.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()ConnectedRepoinitialOwnPropsownProps리액트 리덕스(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

반응형