Приложение обновляется при обновлении магазина - PullRequest
0 голосов
/ 28 июня 2018

Каждый раз, когда я отправляю действие и обновляю свой магазин, все мое приложение рендерится заново. Я предполагаю, что я делаю что-то не так с моей функцией connect / mapDispatchToProps? Правильно ли передать { ...actions } в качестве второго аргумента моей connect функции в App.js?

Вот мой код:

class App extends Component {
  componentDidMount() {
    this.props.fetchPages(api.API_PAGES);
    this.props.fetchPosts(api.API_POSTS);

    window.addEventListener('resize', () => {
      this.props.resizeScreen(window.innerWidth);
    });
  }

  render() {
    return (
      <div>
        {this.props.app.showIntro && <Intro {...this.props} endIntro={this.props.endIntro} />}

        {!this.props.pages.isFetching && this.props.pages.data &&
          <div>
            <Navbar {...this.props} />

            <Layout {...this.props}>
              <Switch location={this.props.location}>
                <Route
                  path={routes.HOME}
                  exact
                  component={() => (
                    <Home {...this.props} />
                  )}
                />
                <Route
                  path={routes.ABOUT}
                  component={() => (
                    <About {...this.props} />
                  )}
                />
                <Route
                  path={routes.NEWS}
                  exact
                  component={() => (
                    <News {...this.props} />
                  )}
                />
                <Route
                  component={NotFound}
                />
              </Switch>
            </Layout>
          </div>
        }
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    app: state.app,
    pages: state.pages,
    posts: state.posts
  };
}

export default withRouter(connect(
  mapStateToProps,
  { ...actions }
)(App));

действия / index.js

export function resizeScreen(screenWidth) {
  return {
    type: types.RESIZE_SCREEN,
    screenWidth
  };
}

export function endIntro() {
  return {
    type: types.END_INTRO,
    showIntro: false
  };
}

export function toggleNav(bool) {
  return {
    type: types.TOGGLE_NAV,
    navOpen: bool
  };
}

export function toggleVideoPlayer(bool) {
  return {
    type: types.TOGGLE_VIDEO_PLAYER,
    videoIsPlaying: bool
  };
}

export function toggleScroll(bool) {
  return {
    type: types.TOGGLE_SROLL,
    disableScroll: bool
  };
}


// pages

function requestPages() {
  return {
    type: types.REQUEST_PAGES
  };
}

function receivePages(data) {
  return {
    type: types.RECEIVE_PAGES,
    data
  };
}


// posts

function requestPosts() {
  return {
    type: types.REQUEST_POSTS
  };
}

function receivePosts(data) {
  return {
    type: types.RECEIVE_POSTS,
    data
  };
}


// creators

export function fetchPages(path) {
  return (dispatch, getState) => {

    const { pages } = getState();

    if (pages.isFetching) return;

    dispatch(requestPages());
    fetch(`${process.env.API_URL}${path}`)
      .then(response => response.json())
      .then(json => dispatch(receivePages(json)));
  };
}

export function fetchPosts(path) {
  return (dispatch, getState) => {

    const { posts } = getState();

    if (posts.isFetching) return;

    dispatch(requestPosts());
    fetch(`${process.env.API_URL}${path}`)
      .then(response => response.json())
      .then(json => dispatch(receivePosts(json)));
  };
}

редукторы / app.js:

const initialState = {
  screenWidth: typeof window === 'object' ? window.innerWidth : null,
  showIntro: true,
  navOpen: false,
  videoIsPlaying: false,
  disableScroll: false
};

export default function app(state = initialState, action) {
  switch (action.type) {

    case RESIZE_SCREEN: {
      return {
        ...state,
        screenWidth: action.screenWidth
      };
    }

    case TOGGLE_NAV: {
      return {
        ...state,
        navOpen: !state.navOpen
      };
    }

    case END_INTRO: {
      return {
        ...state,
        showIntro: false
      };
    }

    case TOGGLE_VIDEO_PLAYER: {
      return {
        ...state,
        videoIsPlaying: !state.videoIsPlaying
      };
    }

    case TOGGLE_SCROLL: {
      return {
        ...state,
        disableScroll: !state.disableScroll
      };
    }

    default: {
      return state;
    }
  }
}

redurs / posts.js похож на redurs / pages.js:

const initialState = {
  isFetching: false
};

export default function posts(state = initialState, action) {
  switch (action.type) {

    case REQUEST_POSTS: {
      return {
        ...state,
        isFetching: true
      };
    }

    case RECEIVE_POSTS: {
      return {
        ...state,
        isFetching: false,
        data: action.data
      };
    }

    default: {
      return state;
    }
  }
}

Ответы [ 2 ]

0 голосов
/ 28 июня 2018

Вот как должен работать редукс: меняется реквизит, поэтому подключенный компонент перерисовывается.

Вы можете:

  • реализует ваш shouldComponentUpdate для ограничения повторного отображения ( примечание : это также предотвратит подкомпоненты)
  • используйте PureComponent вместо Component базового класса, чтобы вы переключились на поверхностное сравнение
  • Ограничить количество подключенных реквизитов, возможно, вместо этого вы можете подключить подкомпоненты.
0 голосов
/ 28 июня 2018

Если у вас возникла проблема с перерасчетом слишком большого количества приложений при каждом обновлении Redux, это помогает использовать больше подключенных компонентов и ограничивать количество передаваемых состояний каждому из них. Я вижу, что вы распределяете реквизиты вниз на каждую страницу, это удобно, но это частая причина неэффективных повторных рендеров.

<Home  {...this.props} />
<About {...this.props} />
<News  {...this.props} />

Это может привести к тому, что в каждый из этих компонентов будет передано слишком много данных, и каждое избыточное действие приведет к повторной визуализации всей страницы.

Другая потенциальная проблема, которую я вижу, заключается в том, что вы используете встроенную анонимную функцию в качестве компонента обратного вызова для ваших маршрутов

<Route
    path={routes.ABOUT}
    component={() => (
        <About {...this.props} />
    )}
/>

Я не совсем уверен, как работает React Router, но потенциальная проблема заключается в том, что каждый раз при повторной визуализации маршрутизатора эти анонимные функции снова создаются совершенно новыми. React увидит их как новый компонент и произведет повторную визуализацию. Вы можете решить эту проблему, сделав каждый из этих компонентов подключенным компонентом, который подключает свои собственные реквизиты, а затем обновите маршрутизатор следующим образом:

<Route
    path={routes.ABOUT}
    component={ConnectedAbout}
/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...