我对React生命周期有些困惑,特别是 componentDidMount 与redux交互的方式。
在这种情况下:我有一个组件连接到redux存储,并且我不知道是否应该在更新Redux存储并且连接的组件中的props改变时再次调用componentDidMount。现在,每次更换道具时都会重新安装一个组件。但是,我还有另一个单独的连接组件,当其支柱发生更改时不会重新安装。所以现在我因为这种不一致的行为而迷路了。
我环顾四周,但有些答案像 Why is componentDidMount not being called when I re-render?和ComponentDidMount called multiple times使我感到困惑。
下面是一个示例,当道具更改时,代码无法正确更新
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from "redux";
import PropTypes from 'prop-types';
/* material UI */
import Collapse from '@material-ui/core/Collapse';
import Divider from '@material-ui/core/Divider';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import Tooltip from '@material-ui/core/Tooltip';
/* Icons */
import {Copy,FolderMinus,FolderPlus} from 'react-feather';
/* Our Components */
import { history } from '../../redux/store/index';
import { getClusters, setCluster, toggleClusters } from '../../redux/actions/ClusterActions';
class SideClustersList extends Component{
constructor(props){
super(props);
}
componentDidMount(){
/* get a list of clusters based on the apiurl */
console.log("props get clusters")
console.log(this.props.base_url)
this.props.getClusters(this.props.base_url);
}
setCurrentCluster(cluster) {
this.props.setCluster(this.props.base_url, cluster)
// Switch tabs to display selected cluster
history.push("/clusters")
}
render(){
const { classes,clusters, open } = this.props;
return (
<React.Fragment>
<ListItem button className={classes.nested} onClick={this.handleClick}>
<Tooltip id="tooltip-bottom" title="Clusters" placement="top">
<ListItemIcon >
{open ? <FolderMinus/>:<FolderPlus/>}
</ListItemIcon>
</Tooltip>
<ListItemText primary="Clusters" /></ListItem>
<Collapse in={open} timeout="auto" unmountOnExit>
<Divider />
<List component="div" disablePadding>
{clusters ? (
clusters.map(cls =>(
<ListItem button key={cls.clusterName} component='a'
/*href={'/clusters/'+this.props.accounts[0]['account_name']+'/'+cls.clusterName}*/
onClick={() => this.setCurrentCluster(cls.clusterName)}>
<Tooltip id="tooltip-top" title={cls.clusterName} placement="top">
<ListItemIcon>
<Copy />
</ListItemIcon>
</Tooltip>
<ListItemText primary={cls.clusterName} />
</ListItem>
))): null}
</List>
</Collapse>
</React.Fragment>
)
}
handleClick = () => {
this.props.toggleClusters(!this.props.open)
};
}
SideClustersList.propTypes = {
getClusters: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
account_name: state.accounts.item.account_name,
base_url: state.accounts.item.apiurl,
cluster: state.clusters.item,
clusters: state.clusters.items,
open: state.clusters.open,
});
function mapDispatchToProps(dispatch) {
return bindActionCreators({getClusters, setCluster, toggleClusters}, dispatch)
}
export default connect(
mapStateToProps, mapDispatchToProps
)(SideClustersList);
答案 0 :(得分:2)
当Redux获取新数据时,它通过向下连接到所有连接的组件触发道具更改。根据商店的变化,组件的行为可能有一些可能性:
当到商店的连接不影响组件的父代时,它将启动常规的组件生命周期:
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
发生这种情况时,该组件将不会调用componentDidMount
。
当孩子的父母受到影响时,有可能将该组件从dom中删除并再次输入。什么时候有可能?例如,当父级组件确定所提供的道具是新道具时,应重新渲染其所有子级。发生这种情况时,请输入从dom卸载组件的路径,然后调用componentWillUnmount()
,然后使用常规的生命周期方法再次进行装载:
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
您可以在此处了解有关和解的更多信息:https://reactjs.org/docs/reconciliation.html
答案 1 :(得分:1)
React使用Reconciliation来确定何时应卸载组件然后重新安装。 React会进行差异检查,以确定何时更新组件及其所有子组件。在父级上没有任何更改时,它不会重新安装任何组件,因此,如果仅更改了组件子级的某些方面,则不会再次调用componentDidMount。因此,如果您提供了返回新组件组的另一种可能性,例如,如果异步获取状态时返回了活动指示器,那么每次重新安装不同的组件组时,您都会得到componentDidMount调用。>