奇怪的问题。基本上,我的生命周期事件不会响应特定的道具变化而触发。这是一个React / Redux应用程序,这里是粗略的层次结构:
组件:
仪表板
--export
--Analytics
---- CreateGraphsDialog
减速:
DashboardReducer
ExportReducer
AnalyticsReducer
索引
操作:
仪表板
出口
分析
使用仪表板,导出和分析组件中的选择字段更改有问题的道具。它使用Dashboard操作和DashboardReducer更新,并通过mapStateToProps访问。当我尝试从主仪表板页面触发生命周期事件(例如componentWillReceiveProps或componentWillUpdate)时,它可以完美地工作。但是尝试从任一子页面“导出”或“分析”访问它们都会失败。道具更新,但其更新不会触发事件。
注意,有问题的道具/物品是一个字符串,所以我不认为这是一个不变性问题......除非其他减速器的不变性可能导致问题。还值得注意的是,组件是更新以响应这些prop更改,并且prop已更改......它只是未触发的生命周期事件。
以下是一些代码:
仪表板操作
import axios from 'axios';
const qs = require('querystring-browser');
export const GOT_INVESTIGATIONS = 'got_investigations';
export const INVESTIGATIONS_ERROR = 'investigations_error';
export const SAVED_INVESTIGATION = 'saved_investigation';
export function getInvestigationsAction() {
return async (dispatch) => {
try {
let jwtlocal = localStorage.getItem('user');
let uri;
if (process.env.NODE_ENV === 'production') {
uri = window.location.protocol + '//' + window.location.host + '/jwtInvestigations'
} else {
uri = 'https://test.teamscope.co/jwtInvestigations'
}
const res = await axios.get(`${uri}`, {headers: {'TS-JWT': jwtlocal}});
dispatch({type: GOT_INVESTIGATIONS, payload: res.data.investigations})
} catch (error) {
console.error(error)
dispatch({
type: INVESTIGATIONS_ERROR,
payload: 'Error retrieving investigations. Please try again, or contact an administrator.'
})
}
}
}
export function saveInvestigationAction(invest) {
return async (dispatch) => {
try {
console.log("InvestInSave:", invest)
dispatch({type: SAVED_INVESTIGATION, payload: invest})
} catch (error) {
console.error("SAVED_INVESTIGATION ERROR")
console.error(error)
}
}
}
DashboardReducer:
import { GOT_INVESTIGATIONS, INVESTIGATIONS_ERROR, SAVED_INVESTIGATION } from '../actions/dashboard';
const initialState = {
};
export default function(state=initialState, action) {
switch(action.type) {
case GOT_INVESTIGATIONS:
return { ...state, investsData: action.payload, investsError: undefined };
case INVESTIGATIONS_ERROR:
return { ...state, investsError: action.payload };
case SAVED_INVESTIGATION:
return { ...state, savedInvest: action.payload };
}
return state;
}
分析组件:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Button from 'material-ui/Button';
import TextField from 'material-ui/TextField';
import Table, { TableBody, TableCell, TableHead, TableRow } from 'material-ui/Table';
import Paper from 'material-ui/Paper';
import CreateGraphsDialog from './CreateGraphsDialog';
import Cached from 'material-ui-icons/Cached';
import { withRouter } from 'react-router-dom';
import { withStyles } from 'material-ui/styles';
import { connect } from 'react-redux';
import { getSavedGraphsAction, deleteGraphsAction, getGraphAction } from '../../actions/analytics';
import compose from 'recompose/compose';
const Highcharts = require('highcharts');
require('highcharts/modules/exporting')(Highcharts);
const ReactHighcharts = require('react-highcharts');
class Analytics extends Component {
constructor(props) {
super(props);
this.props.getSavedGraphsAction(this.props.investigation);
}
componentWillUpdate(nextProps) {
console.log(this.props.investigation)
console.log(nextProps.investigation)
//These consoles only fire if a *different* prop is changed, and even then they only ever show the same value for each.
if (this.props.investigation && nextProps.investigation) {
if (this.props.investigation !== nextProps.investigation) {
console.log("!")
//This console never fires.
this.props.getSavedGraphsAction(nextProps.investigation)
}
}
}
refreshGraphs = () => {
this.props.graphData.forEach((graph) => {
this.props.getGraphAction(graph.values);
});
};
render() {
let graphs = null;
if (this.props.graphData.length > 0) {
console.log("graphs:", this.props.graphData)
this.props.graphData.forEach((graph, i) => {
if (graph.values.chartType !== 'basic') {
graph.config.exporting = {
buttons: {
deleteButton: {
enabled: true,
text: "Delete",
onclick: () => { this.props.deleteGraphsAction(graph.values.identifier) }
}
}
}
}
})
graphs = (
<div>
{this.props.graphData.map((graph) =>
{ return graph.values.chartType === 'basic' ?
<div className="graphs">
<Table className={this.props.classes.table}>
<TableHead>
<TableRow>
<TableCell>Survey Name</TableCell>
<TableCell numeric>Minimum</TableCell>
<TableCell numeric>Maximum</TableCell>
<TableCell numeric>Mean</TableCell>
<TableCell numeric>Standard Deviation</TableCell>
<TableCell numeric>Variance</TableCell>
<TableCell numeric>Count</TableCell>
<TableCell><Button primary onClick={() => this.props.deleteGraphsAction(graph.values.identifier)}>Delete</Button></TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>{graph.config.surveyTitle}</TableCell>
<TableCell numeric>{graph.config.stats.min}</TableCell>
<TableCell numeric>{graph.config.stats.max}</TableCell>
<TableCell numeric>{graph.config.stats.mean}</TableCell>
<TableCell numeric>{graph.config.stats.stdDev}</TableCell>
<TableCell numeric>{graph.config.stats.var}</TableCell>
<TableCell numeric>{graph.config.stats.count}</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
: <div className="graphs">
<ReactHighcharts config={graph.config}/>
</div> }
)}
</div>
)
} else if (!this.props.investigation) {
graphs = "Please select an investigation from the top right selection menu.";
} else {
graphs = null;
}
return (
<div>
<CreateGraphsDialog/>
<Button className={this.props.classes.refresh} onClick={this.refreshGraphs}>
Refresh <Cached/>
</Button>
{graphs}
</div>
);
}
}
const styles = {
margin: 15,
table: {
minWidth: 700,
},
refresh: {
},
graphs: {
}
};
function mapStateToProps(state, ownProps) {
return {
investigation: state.dashboard.savedInvest,
graphData: state.analytics.graphData,
graphError: state.analytics.graphError
};
}
export default compose(
withRouter,
connect(mapStateToProps, {getSavedGraphsAction, deleteGraphsAction, getGraphAction}),
withStyles(styles)
)(Analytics);
-------------- UPDATE ---------------
我刚尝试了一个全新的组件,没有添加所有额外的东西。这是一个子组件,就像Analytics一样。它有同样的问题。这是代码:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { withRouter } from 'react-router-dom';
import { withStyles } from 'material-ui/styles';
import { connect } from 'react-redux';
import { getAuditsAction } from '../../actions/auditTrail';
import PropTypes from 'prop-types';
import compose from 'recompose/compose';
class AuditTrail extends Component {
constructor(props){
super(props);
this.props.getAuditsAction(this.props.investigation)
}
componentWillUpdate(nextProps) {
//These don't get called at all, since there aren't any other props to muddy the waters.
console.log(this.props.investigation);
console.log(nextProps.investigation);
}
render() {
let notification;
if (!this.props.investigation) {
notification = "Please select an investigation from the top right selection menu.";
} else if (this.props.auditError) {
notification = this.props.auditError;
}
return (
<div>
{notification}
</div>
)
}
}
const styles = {
formContainer: {
width: '30%'
}
};
function mapStateToProps(state, ownProps) {
return {
investigation: state.dashboard.savedInvest,
audits: state.auditTrail.auditData,
auditError: state.auditTrail.auditError
};
}
export default compose(
withRouter,
connect(mapStateToProps, { getAuditsAction }),
withStyles(styles)
)(AuditTrail);
答案 0 :(得分:1)
来自提供的代码段
DashboardReducer:
case GOT_INVESTIGATIONS : return {
...state,
investsData: action.payload,
investsError: undefined
};
你只做一级浅版。相反,你应该这样做 像这样的状态更新。
return Object.assign({}, JSON.parse(JSON.stringify(state), {
investsData: action.payload,
investsError: undefined
}));