React / Redux:状态在Redux对象中更新,但React组件不会重新呈现

时间:2018-01-25 02:07:08

标签: javascript reactjs redux

试图通过类似的问题,但没有发现类似的问题。

我正在尝试按照我的应用中的名称和金额实施排序,此事件在此组件中触发:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { sortByExpenseName, sortByExpenseAmount } from '../actions/expensesFilters';

class ExpensesListFilter extends Component {
  onSortByExpenseName = () => {
    this.props.sortByExpenseName();
  };

  onSortByExpenseAmount = () => {
    this.props.sortByExpenseAmount();
  }

  render() {
    return (
      <div>
        <span>Expense Name</span>
        <button onClick={this.onSortByExpenseName}>Sort me by name</button>
        <button onClick={this.onSortByExpenseAmount}>Sort me by amount</button>
      </div>
    )
  }
}

const mapDispatchToProps = (dispatch) => ({
  sortByExpenseName: () => dispatch(sortByExpenseName()),
  sortByExpenseAmount: () => dispatch(sortByExpenseAmount()),
});

export default connect(null, mapDispatchToProps)(ExpensesListFilter);

为此我使用了以下选择器:

export default (expenses, { sortBy }) => {
  return expenses.sort((a, b) => {
    if (sortBy === 'name') {
      return a.name < b.name ? 1 : -1;
    } else if (sortBy === 'amount') {
      return parseInt(a.amount, 10) < parseInt(b.amount, 10) ? 1 : -1;
    }
  });
};

我在我的ExpensesList组件的mapStateToProps函数中运行此选择器:

import React from 'react';
import { connect } from 'react-redux';
import ExpensesItem from './ExpensesItem';

// my selector
import sortExpenses from '../selectors/sortExpenses';


const ExpensesList = props => (
  <div className="content-container">
    {props.expenses && props.expenses.map((expense) => {
        return <ExpensesItem key={expense.id} {...expense} />;
    }) }
  </div>
);

// Here I run my selector to sort expenses
const mapStateToProps = (state) => {
  return {
    expenses: sortExpenses(state.expensesData.expenses, state.expensesFilters),
  };
};

export default connect(mapStateToProps)(ExpensesList);

此选择器更新我的过滤器减少器,这会导致我的应用程序状态更新:

import { SORT_BY_EXPENSE_NAME, SORT_BY_EXPENSE_AMOUNT } from '../actions/types';

const INITIAL_EXPENSE_FILTER_STATE = {
  sortBy: 'name',
};

export default (state = INITIAL_EXPENSE_FILTER_STATE, action) => {
  switch (action.type) {
    case SORT_BY_EXPENSE_NAME:
      return {
        ...state,
        sortBy: 'name',
      };
    case SORT_BY_EXPENSE_AMOUNT:
      return {
        ...state,
        sortBy: 'amount',
      };
    default:
      return state;
  }
};

排序事件导致我的状态更新,下面的费用减少器中的费用数组被更新并按选择器排序,但是在我的费用数组状态更新后,ExpensesList组件不会重新呈现。 我希望我的ExpensesList组件做的是使用已排序的费用数组重新呈现并在列表中对ExpensesItem组件进行排序。 它失败的原因是什么?很确定我错过了必不可少的东西,但无法弄清楚是什么。我的费用减少:

import { FETCH_EXPENSES } from '../actions/types';

const INITIAL_STATE = {};

export default (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case FETCH_EXPENSES:
      return {
        ...state,
        expenses: action.expenses.data,
      };
    default:
      return state;
  }
};

所有这些组件都是此父组件的子组件:

import React from 'react';
import ExpensesListFilter from './ExpensesListFilter';
import ExpensesList from './ExpensesList';

const MainPage = () => (
  <div className="box-layout">
    <div className="box-layout__box">
      <ExpensesListFilter />
      <ExpensesList />
    </div>
  </div>
);

export default MainPage;

App.js文件(我运行startExpenseFetch)

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import 'normalize.css/normalize.css';

import AppRouter, { history } from './routers/AppRouter';
import configureStore from './store/configureStore';
import LoadingPage from './components/LoadingPage';
import { startExpenseFetch } from './actions/expensesData';
import './styles/styles.scss';

const store = configureStore();

const jsx = (
  <Provider store={store}>
    <AppRouter />
  </Provider>
);

let hasRendered = false;

const renderApp = () => {
  if (!hasRendered) {
    ReactDOM.render(jsx, document.getElementById('app'));
    hasRendered = true;
  }
};

store.dispatch(startExpenseFetch()).then(() => {
  renderApp();
});

ReactDOM.render(<LoadingPage />, document.getElementById('app'));

其余文件:

ExpenseItem组件:

import React from 'react';

const ExpenseItem = ({ amount, name }) => (
  <div>
    <span>{name}</span>
    <span>{amount}</span>
  </div>
);

export default ExpenseItem;

行动创作者:

expensesData.js

import axios from 'axios';
import { FETCH_EXPENSE } from './types';

// no errors here
const ROOT_URL = '';

export const fetchExpenseData = expenses => ({
  type: FETCH_EXPENSE,
  expenses,
});

export const startExpenseFetch = () => {
  return (dispatch) => {
    return axios({
      method: 'get',
      url: `${ROOT_URL}`,
    })
      .then((response) => {
        dispatch(fetchExpenseData(response));
        console.log(response);
      })
      .catch((error) => {
        console.log(error);
      });
  };
};

expensesFilters.js

import { SORT_BY_EXPENSE_NAME, SORT_BY_EXPENSE_AMOUNT } from './types';

export const sortByExpenseName = () => ({
  type: SORT_BY_EXPENSE_NAME,
});

export const sortByExpenseAmount = () => ({
  type: SORT_BY_EXPENSE_AMOUNT,
});

configureStores.js文件

import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import expensesDataReducer from '../reducers/expensesData';
import expensesFilterReducer from '../reducers/expensesFilters';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export default () => {
  const store = createStore(
    combineReducers({
      expensesData: expensesDataReducer,
      expensesFilters: expensesFilterReducer,
    }),
    composeEnhancers(applyMiddleware(thunk))
  );
  return store;
};

AppRouter.js文件

import React from 'react';
import { Router, Route, Switch, Link, NavLink } from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import MainPage from '../components/MainPage';
import NotFoundPage from '../components/NotFoundPage';

export const history = createHistory();

const AppRouter = () => (
  <Router history={history}>
    <div>
      <Switch>
        <Route path="/" component={MainPage} exact={true} />
        <Route component={NotFoundPage} />
      </Switch>
    </div>
  </Router>
);

export default AppRouter;

2 个答案:

答案 0 :(得分:0)

你打电话给选择器时输错了吗? :)

// Here I run my selector to sort expenses
const mapStateToProps = (state) => {
  return {
    expenses: sortExpenses(state.expensesData.expenses, state.expnsesFilters),
  };
};

state.expnsesFilters 看起来应该是州。费用过滤器

这是你应该让sortExpenses选择器抓住自己需要的状态部分并自行完成工作的原因之一。你可以测试它的隔离并避免这样的错误。

答案 1 :(得分:0)

我找到了它发生的原因,在我的选择器中我正在改变我的应用程序的状态。我没有从它返回一个新数组,而是改变旧数组,而不是触发我的vue层重新渲染。修复它现在可以使用了。