简体   繁体   English

React / Redux:状态在Redux对象中更新,但是React组件不会重新渲染

[英]React/Redux: State is updated in Redux object, but React component doesn't re-render

Tried to look through similar questions, but didn't find similar issues. 试图浏览相似的问题,但没有找到相似的问题。

I am trying to implement sorts by name and amount in my app, this event is triggered in this component: 我正在尝试在应用中按名称和数量实现排序,此事件在此组件中触发:

 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); 

for that I am using following selector: 为此,我正在使用以下选择器:

 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; } }); }; 

I run this selector in mapStateToProps function for my ExpensesList component here: 我在mapStateToProps函数中为ExpensesList组件运行此选择器:

 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); 

This selector updates my filter reducer, which causes my app state to update: 此选择器更新了我的过滤器缩减器,这导致我的应用程序状态更新:

 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; } }; 

Sort event causes my state to update, the expenses array in my expenses reducer below is updated and sorted by selector, BUT the ExpensesList component doesn't re-render after my expenses array in state is updated. 排序事件导致我的状态更新,下面的我的费用减少器中的费用数组已更新,并通过选择器进行了排序,但在我的费用数组更新后,ExpensesList组件不会重新呈现。 What I want my ExpensesList component to do, is to re-render with sorted expenses array and sort ExpensesItem components in list. 我希望ExpensesList组件执行的操作是使用已排序的费用数组重新渲染并在列表中对ExpensesItem组件进行排序。 What could be the reason why it fails? 失败的原因可能是什么? Pretty sure I am missing out something essential, but can't figure out what. 可以肯定的是,我错过了一些必不可少的东西,但无法弄清楚是什么。 My expenses reducer: 我的费用减少者:

 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; } }; 

All these components are childs to this parent component: 所有这些组件都是此父组件的子代:

 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 file (where I run startExpenseFetch) 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')); 

Rest of files: 其余文件:

ExpenseItem Component: ExpenseItem组件:

 import React from 'react'; const ExpenseItem = ({ amount, name }) => ( <div> <span>{name}</span> <span>{amount}</span> </div> ); export default ExpenseItem; 

Action creators: 动作创作者:

expensesData.js experienceData.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 experienceFilters.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 file 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 file 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; 

Don't you have a typo on your call to your selector? 您拨打选择器时没有打错字吗? :) :)

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

state.expnsesFilters look like it should be state. state.expnsesFilters看起来应该是状态。 expenses Filters 费用过滤器

Which is one of the reasons you should make your sortExpenses selector grab itself the parts of the state it needs and do it's job on its own. 这是您应让sortExpenses选择器自行获取所需状态的一部分并自行完成工作的原因之一。 You could test it isolation and avoid mistakes like this. 您可以对其进行隔离测试,并避免出现此类错误。

I found a reason why it happens, in my selector I was mutating my app's state. 我发现了发生这种情况的原因,在选择器中,我正在改变应用程序的状态。 I wasn't returning a new array from it, and was changing the old one instead, that didn't trigger my vue layer to re-render. 我没有从中返回新的数组,而是在改变旧的数组,这并没有触发我的vue层重新渲染。 Fixed it and it works now. 修复了它,现在可以使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 更改Redux状态时,组件不会重新渲染-React - Component doesn't re-render when Redux state is changed - React Redux、React 状态更新和重新渲染组件 - Redux, React state update and re-render component 使用 react、redux 和 immer 更新状态时,组件不会重新渲染 - Component does not re-render when State is updated using react, redux and immer 当 redux 连接状态改变时,有状态的本机功能组件不会重新渲染 - Stateful react-native functional component don't re-render when redux connected state change 当状态改变时,redux的带有连接助手的本机反应不会重新呈现吗? - React native with connect helper from redux doesn't re-render when state change? 在redux中更新了状态,以接收新道具,但是由于未重新渲染组件而未在componentWillReceiveProps中设置状态 - State updated in redux receiving new props but state is not setting in componentWillReceiveProps due to which component doesn't re-render 尽管Redux状态已更新,但组件未重新渲染 - Component does not re-render although redux state is updated <Redux>状态更新但不重新渲染 - <Redux> state updated but nor re-render React JS状态更改不会重新渲染组件 - React JS state change doesn't re-render the component 状态更改时,React组件不会重新呈现 - React component doesn't re-render when state changes
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM