Как остановить накопление данных в хранилище состояний в избыточном компоненте при каждом переходе к нему с помощью реагирующего маршрутизатора - PullRequest
0 голосов
/ 25 января 2020

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

У меня есть ряд компонентов, которые перечисляют сообщения, страницы и различные типы пользовательских сообщений, взятых из WordPress API и я перемещаюсь между ними с помощью response-router-dom.

Проблема в том, что каждый раз, когда я go возвращаюсь к компоненту / просматриваю список постов или страниц, отображается снова, например, в первый раз, когда я go, список может быть следующим: тестовый пост 1, тестовый пост 2, второй раз: тестовый пост 1, тестовый пост 2, тестовый пост 1, тестовый пост 2, в третий раз: тестовый пост 1, тестовый пост 2, тестовый пост 1, тестовый пост 2, тестовый пост 1, тестовый пост 2 et c et c et c.

Причина этого очевидна, каждый раз, когда Компонент отображается, однако данные извлекаются из хранилища и обрабатываются, поскольку все приложение не выполняет рендеринг так, как это было бы с простым старым reactjs, оно не очищается.

Мой вопрос конечно Каков наилучший способ исправить это? Я прочитал некоторые связанные посты, которые советуют прикрепить какое-то условие к компоненту, чтобы проверить, присутствуют ли данные, но я не знаю, как это сделать, и не могу узнать, как. Мои попытки не сработали, потому что кажется, что любая переменная, возвращенная из componentDidMount, не видна в методе рендеринга.

Заранее спасибо.

Код ниже:

src /index.js

import React from "react";
import { BrowserRouter as Router } from 'react-router-dom';
import { render } from "react-dom";
import { Provider } from "react-redux";
import store from "./js/store/index";
import App from "./js/components/App";
render(
  <Router>
    <Provider store={store}>
      <App />
    </Provider>
  </Router>,
  document.getElementById("root")
);

src / js / index. js

import store from "../js/store/index";
window.store = store;

src / js / store / index. js

import { createStore, applyMiddleware, compose } from "redux";
import rootReducer from "../reducers/index";
import thunk from "redux-thunk";
const storeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  rootReducer,
  storeEnhancers(applyMiddleware(thunk))
);
export default store;

src / js / redurs / index. js

import { POSTS_LOADED } from "../constants/action-types";
import { PAGES_LOADED } from "../constants/action-types";

const initialState = {
  posts: [],
  pages: [],
  banner_slides: [],
  portfolio_items: []
};

function rootReducer(state = initialState, action) {

    switch (action.type) {
      case 'POSTS_LOADED':
          return Object.assign({}, state, {
            posts: state.posts.concat(action.payload)
          });

      case 'PAGES_LOADED':
          return Object.assign({}, state, {
            pages: state.pages.concat(action.payload)
          });

      default: 
          return state;
    }
}

export default rootReducer;

src / js / actions / index. js

export function getWordpress(endpoint) {
    return function(dispatch) {
        return fetch("http://localhost/all_projects/react-wpapi/my_portfolio_site/wordpress/wp-json/wp/v2/" + endpoint )
            .then(response => response.json())
            .then(json => { 
            dispatch({ type: endpoint.toUpperCase() + "_LOADED", payload: json });
        });
    };
}

src / js / constants / action -типы. js

export const ADD_ARTICLE = "ADD_ARTICLE";
export const POSTS_LOADED = "POSTS_LOADED";
export const PAGES_LOADED = "PAGES_LOADED";

src / js / components / app. js

import React from "react";
import { Route, Switch, Redirect } from 'react-router-dom';

import Header from "./Header/Header";
import Posts from "./Posts";
import Pages from "./Pages";
import BannerSlides from "./BannerSlides";
import PortfolioItems from "./PortfolioItems";

const App = () => (
    <div>
        <Header />
        <Route render = {({ location }) => (
            <Switch location={location}>
            <Route 
                exact path="/posts"
                component={Posts} 
            />   
            <Route 
                exact path="/pages"
                component={Pages} 
            />   
            </Switch>
        )} />
    </div>
);
export default App;

src / js / components / Posts. js

import React, { Component } from "react";
import { connect } from "react-redux";
import { getWordpress } from "../actions/index";
export class Posts extends Component {

  componentDidMount() {
      this.props.getWordpress('posts');
      let test = 1;
      return test;
  }

  render() {
    console.log("test: ", test); // not defined
      if (test !== 1) { 
          return (
            <ul>
              {this.props.posts.map(item => ( 
                <li key={item.id}>{item.title.rendered}</li>
              ))}
            </ul>
          );
      }
  }
}
function mapStateToProps(state) {
    return {
        posts: state.posts.slice(0, 10)
    };
}
export default connect(
  mapStateToProps,
  { getWordpress }
)(Posts);

Ответы [ 3 ]

1 голос
/ 25 января 2020

Если я понимаю, вы хотите получать только первые сообщения при первом монтировании, а не каждый раз, когда компонент монтируется?

В src/js/components/Posts.js вы можете проверить, хранятся ли какие-либо посты в Redux, прежде чем извлекать внутри метода жизненного цикла CDM. Например,

componentDidMount() {
  // access props.posts which you set inside mapDispatchToProps
  if (this.props.posts.length === 0) {
    this.props.getWordpress('posts');
  }
}

Если у вас все в порядке с дублирующими вызовами API на каждом монтировании, и вы можете получать все посты сразу, вы можете настроить редуктор так, чтобы он переписывал массив постов вместо concat. Но перезапись предполагает, что вы хотите загрузить все сообщения за 1 вызов API, вместо того, чтобы загружать, скажем, 25 сообщений на страницу или иметь кнопку «Загрузить больше сообщений».

1 голос
/ 25 января 2020

Вам нужно проверить свое состояние перед вызовом fetch. Мне нравится помещать mst моего логика c в редукционную часть приложения (создатели с толстым действием) и использовать мои компоненты реакции только для рендеринга текущего состояния. Я бы порекомендовал что-то вроде этого:

    export function getWordpress(endpoint) {
        return function(dispatch, getState) {
            const currentState = getState();
            if (currentState.posts && currentState.posts.length) {
            // already initialized, can just return current state
                return currentState.posts;
            }
            return fetch("http://localhost/all_projects/react-wpapi/my_portfolio_site/wordpress/wp-json/wp/v2/" + endpoint )
                .then(response => response.json())
                .then(json => { 
                dispatch({ type: endpoint.toUpperCase() + "_LOADED", payload: json });
            });
        };
    }

Позже вы можете разделить логи c, если посты инициализируются в селектор, и добавить несколько дополнительных слоев (например, если посты устарели). Таким образом, ваша «деловая» логика c легко тестируется и отделена от вашего пользовательского интерфейса.

Надеюсь, это поможет:)

1 голос
/ 25 января 2020

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

function rootReducer(state = initialState, action) {
switch (action.type) {
  case 'POSTS_LOADED':
      return {
        ...state,
        posts: action.payload
      };

  case 'PAGES_LOADED':
      return {
        ...state,
        pages: action.payload
      };

  default: 
      return state;
 }
}

Надеюсь, это поможет:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...