React/Redux:尽管调度和状态更改正确,但组件未重绘。 (不涉及突变)
React/Redux: Component not redrawing despite correct dispatching and state change. (no mutation involved)
我的 redux 应用程序有问题:它正确地分派相关操作并更新状态,但由于某种原因 UI 没有得到更新。 99% 的问题似乎是因为状态实际上发生了变异,但我很确定情况并非如此。以下是相关文件:
容器组件:
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import requestEvents from 'actions/feedActions';
import { FeedElement, feedElementTypes } from '../components/feed/feedElement';
class Feed extends React.Component {
componentWillMount() {
this.props.requestEvents();
}
render() {
console.log('Rendering feed');
const listOfFeedElements = this.props.listOfFeedElements;
let elementsToDisplay;
if (listOfFeedElements.length === 0) {
elementsToDisplay = <li><p> No elements to display</p></li>;
} else {
const numOfElementsToDisplay = listOfFeedElements.length <= 10 ?
listOfFeedElements.length : 10;
const sortedElementsToDisplay = listOfFeedElements.concat().sort(
(e1, e2) => e1.timestamp - e2.timeStamp);
elementsToDisplay =
sortedElementsToDisplay
.slice(0, numOfElementsToDisplay)
.map(el => FeedElement(el));
}
return (
<div className="socialFeedContainer">
<h1> Social feed </h1>
<ol>
{elementsToDisplay}
</ol>
</div>
);
}
}
Feed.propTypes = {
requestEvents: PropTypes.func.isRequired,
listOfFeedElements: PropTypes.arrayOf(PropTypes.shape({
timeStamp: PropTypes.number.isRequired,
type: PropTypes.oneOf(Object.keys(feedElementTypes)).isRequired,
targetDeck: PropTypes.string.isRequired,
concernedUser: PropTypes.string.isRequired,
viewed: PropTypes.bool.isRequired })),
};
Feed.defaultProps = {
listOfFeedElements: [],
};
function mapDispatchToProps(dispatch) {
return bindActionCreators({ requestEvents }, dispatch);
}
function mapStateToProps(state) {
const { feedState } = state.local.feed.listOfFeedElements;
return {
feedState,
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Feed);
减速器:
import Immutable from 'seamless-immutable';
import { types } from 'actions/feedActions';
const initialState = Immutable({
listOfFeedElements: [],
sentRequestForList: false,
receivedList: false,
});
function feedReducer(state = initialState, action) {
switch (action.type) {
case types.REQUEST_FEED_ELEMENTS:
return Immutable.merge(state, {
sentRequestForList: true,
receivedList: false,
});
case types.RECEIVED_LIST:
return Immutable.merge(state, {
sentRequestForList: false,
receivedList: true,
listOfFeedElements: action.payload.listOfNotifications,
});
default:
return state;
}
}
export default feedReducer;
传奇:
import { takeLatest, put } from 'redux-saga/effects';
import { types } from 'actions/feedActions';
import feedApiCall from './feedApiCall';
export function* getFeedFlow() {
try {
console.log('sent request for feed');
const listOfNotifications = feedApiCall();
yield put({
type: types.RECEIVED_LIST,
payload: {
listOfNotifications,
},
});
} catch (error) {
yield put({
type: types.RECEPTION_ERROR,
payload: {
message: error.message,
statusCode: error.statusCode,
},
});
}
}
function* feedUpdateWatcher() {
yield takeLatest(types.REQUEST_FEED_ELEMENTS, getFeedFlow);
}
export default feedUpdateWatcher;
动作被分派并且状态被修改(最后我有一个包含组件的列表)。然而,该组件仅呈现一次,因为我可以从对 console.log 的调用中进行检查。
根组件看起来很可疑。
首先,从代码和命名约定出发,FeedElement class 看起来像React,但是它在map中用作简单的函数。有没有类似的观点看东西:
elementsToDisplay =
sortedElementsToDisplay
.slice(0, numOfElementsToDisplay)
.map(el => (<FeedElement {...el} />));
其次,您 return 对象 const {feedState} = state.local.feed.listOfFeedElements;
并进一步解决 this.props.listOfFeedElements
- 这样的字段原则上不存在。 state.local.feed
的一部分从哪里开始?
另外,当你被redux和saga使用的时候,一般最好做一个纯函数式的部分,去掉对componentWillMount的调用,它与预期的架构不符。
我的 redux 应用程序有问题:它正确地分派相关操作并更新状态,但由于某种原因 UI 没有得到更新。 99% 的问题似乎是因为状态实际上发生了变异,但我很确定情况并非如此。以下是相关文件:
容器组件:
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import requestEvents from 'actions/feedActions';
import { FeedElement, feedElementTypes } from '../components/feed/feedElement';
class Feed extends React.Component {
componentWillMount() {
this.props.requestEvents();
}
render() {
console.log('Rendering feed');
const listOfFeedElements = this.props.listOfFeedElements;
let elementsToDisplay;
if (listOfFeedElements.length === 0) {
elementsToDisplay = <li><p> No elements to display</p></li>;
} else {
const numOfElementsToDisplay = listOfFeedElements.length <= 10 ?
listOfFeedElements.length : 10;
const sortedElementsToDisplay = listOfFeedElements.concat().sort(
(e1, e2) => e1.timestamp - e2.timeStamp);
elementsToDisplay =
sortedElementsToDisplay
.slice(0, numOfElementsToDisplay)
.map(el => FeedElement(el));
}
return (
<div className="socialFeedContainer">
<h1> Social feed </h1>
<ol>
{elementsToDisplay}
</ol>
</div>
);
}
}
Feed.propTypes = {
requestEvents: PropTypes.func.isRequired,
listOfFeedElements: PropTypes.arrayOf(PropTypes.shape({
timeStamp: PropTypes.number.isRequired,
type: PropTypes.oneOf(Object.keys(feedElementTypes)).isRequired,
targetDeck: PropTypes.string.isRequired,
concernedUser: PropTypes.string.isRequired,
viewed: PropTypes.bool.isRequired })),
};
Feed.defaultProps = {
listOfFeedElements: [],
};
function mapDispatchToProps(dispatch) {
return bindActionCreators({ requestEvents }, dispatch);
}
function mapStateToProps(state) {
const { feedState } = state.local.feed.listOfFeedElements;
return {
feedState,
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Feed);
减速器:
import Immutable from 'seamless-immutable';
import { types } from 'actions/feedActions';
const initialState = Immutable({
listOfFeedElements: [],
sentRequestForList: false,
receivedList: false,
});
function feedReducer(state = initialState, action) {
switch (action.type) {
case types.REQUEST_FEED_ELEMENTS:
return Immutable.merge(state, {
sentRequestForList: true,
receivedList: false,
});
case types.RECEIVED_LIST:
return Immutable.merge(state, {
sentRequestForList: false,
receivedList: true,
listOfFeedElements: action.payload.listOfNotifications,
});
default:
return state;
}
}
export default feedReducer;
传奇:
import { takeLatest, put } from 'redux-saga/effects';
import { types } from 'actions/feedActions';
import feedApiCall from './feedApiCall';
export function* getFeedFlow() {
try {
console.log('sent request for feed');
const listOfNotifications = feedApiCall();
yield put({
type: types.RECEIVED_LIST,
payload: {
listOfNotifications,
},
});
} catch (error) {
yield put({
type: types.RECEPTION_ERROR,
payload: {
message: error.message,
statusCode: error.statusCode,
},
});
}
}
function* feedUpdateWatcher() {
yield takeLatest(types.REQUEST_FEED_ELEMENTS, getFeedFlow);
}
export default feedUpdateWatcher;
动作被分派并且状态被修改(最后我有一个包含组件的列表)。然而,该组件仅呈现一次,因为我可以从对 console.log 的调用中进行检查。
根组件看起来很可疑。
首先,从代码和命名约定出发,FeedElement class 看起来像React,但是它在map中用作简单的函数。有没有类似的观点看东西:
elementsToDisplay =
sortedElementsToDisplay
.slice(0, numOfElementsToDisplay)
.map(el => (<FeedElement {...el} />));
其次,您 return 对象 const {feedState} = state.local.feed.listOfFeedElements;
并进一步解决 this.props.listOfFeedElements
- 这样的字段原则上不存在。 state.local.feed
的一部分从哪里开始?
另外,当你被redux和saga使用的时候,一般最好做一个纯函数式的部分,去掉对componentWillMount的调用,它与预期的架构不符。