parent 的 setState 不会触发 child 的 componentWillReceiveProps
setState of parent does not fire componentWillReceiveProps of child
我有一个组件 parent 和一个组件 child,其中一些道具连接到 parent 状态。
在 parent 中我调用了 setState 但 child 的 componentWillReceiveProps
函数没有触发。
更准确地说,它在 parent 的某个点被触发,而在另一个点没有被触发。
这是parent:
... imports
class HomeScreen extends Component {
constructor(props) {
super(props);
dispatchFbPermissionAction = this.dispatchFbPermissionAction.bind(this);
this.state = {
fbPermissions: [],
}
}
componentDidMount () {
this._loadInitialState();
}
_responsePermissionsCallback(error: ?Object, result: ?Object) {
if (error) {
log('Error fetching data: ' + error.toString());
} else {
dispatchFbPermissionAction(result.data);
}
}
dispatchFbPermissionAction = (data) => {
// **NOT FIRED**
this.setState({
fbPermissions: data
});
this.props.fbPermissionsLoaded(data);
}
async _loadInitialState() {
AccessToken.getCurrentAccessToken().then(
(data) => {
if (data) {
const infoRequest = new GraphRequest(
'/me/permissions',
null,
this._responsePermissionsCallback,
);
new GraphRequestManager().addRequest(infoRequest).start();
// **FIRED**
this.setState({
...
});
this.props.loggedIn();
}
}
);
}
render () {
const { navigation } = this.props;
return (
<Container>
<ScrollableTabView
<View tabLabel="ios-film" style={styles.tabView}>
<Text style={styles.tabTitle}>{_.toUpper(strings("main.theatres"))}</Text>
<ListTheatre navigation={this.props.navigation} filterText={this.state.filterText} isLoggedIn={this.state.isLoggedIn} fbPermissions={this.state.fbPermissions}></ListTheatre>
</View>
</ScrollableTabView>
</Container>
)
}
}
const mapStateToProps = (state) => {
return {
isLoggedIn: state.isLoggedIn,
listTheatre: state.listTheatre,
listMusic: state.listMusic
};
};
// wraps dispatch to create nicer functions to call within our component
const mapDispatchToProps = (dispatch) => ({
startup: () => dispatch(StartupActions.startup()),
loggedIn: () => dispatch({
type: LOGGED_IN
}),
fbPermissionsLoaded: (data) => dispatch({
type: FB_PERMISSIONS_LOADED,
fbPermissions: data
})
});
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen)
这是 child:
... imports
class ListTheatre extends Component {
constructor(props) {
super(props);
this.state = {
...
}
}
componentWillReceiveProps(nextProps) {
log(this.props)
}
shouldComponentUpdate(nextProps, nextState) {
return !nextState.fetching;
}
render() {
const { navigate } = this.props.navigation;
return (
<SectionList
...
/>
)
}
}
ListTheatre.propTypes = {
isLoggedIn: PropTypes.bool.isRequired,
}
const mapStateToProps = (state) => {
return {
isLoggedIn: state.isLoggedIn
};
};
const mapDispatchToProps = (dispatch) => ({
startup: () => dispatch(StartupActions.startup())
});
export default connect(mapStateToProps, mapDispatchToProps)(ListTheatre);
我不明白为什么 GraphRequestManager().addRequest
调用后的 setState 工作得很好(child 的 componentWillReceiveProps 函数被触发),而 dispatchFbPermissionAction 函数中的 setState 没有触发 componentWillReceiveProps child.
函数
这是由于 connect
/Connect(ListTheatre)
包装了您的 ListTheatre 组件实现的 sCU(shouldComponentUpdate) 内部 为您关闭它,通过设置 pure 将其关闭连接到 false like
的选项
export default connect(mapStateToProps, mapDispatchToProps, null, {pure: false})(ListTheatre)
[pure] (Boolean): If true, connect() will avoid re-renders and calls to mapStateToProps, mapDispatchToProps, and mergeProps if the relevant state/props objects remain equal based on their respective equality checks. Assumes that the wrapped component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. Default value: true
我有一个组件 parent 和一个组件 child,其中一些道具连接到 parent 状态。
在 parent 中我调用了 setState 但 child 的 componentWillReceiveProps
函数没有触发。
更准确地说,它在 parent 的某个点被触发,而在另一个点没有被触发。
这是parent:
... imports
class HomeScreen extends Component {
constructor(props) {
super(props);
dispatchFbPermissionAction = this.dispatchFbPermissionAction.bind(this);
this.state = {
fbPermissions: [],
}
}
componentDidMount () {
this._loadInitialState();
}
_responsePermissionsCallback(error: ?Object, result: ?Object) {
if (error) {
log('Error fetching data: ' + error.toString());
} else {
dispatchFbPermissionAction(result.data);
}
}
dispatchFbPermissionAction = (data) => {
// **NOT FIRED**
this.setState({
fbPermissions: data
});
this.props.fbPermissionsLoaded(data);
}
async _loadInitialState() {
AccessToken.getCurrentAccessToken().then(
(data) => {
if (data) {
const infoRequest = new GraphRequest(
'/me/permissions',
null,
this._responsePermissionsCallback,
);
new GraphRequestManager().addRequest(infoRequest).start();
// **FIRED**
this.setState({
...
});
this.props.loggedIn();
}
}
);
}
render () {
const { navigation } = this.props;
return (
<Container>
<ScrollableTabView
<View tabLabel="ios-film" style={styles.tabView}>
<Text style={styles.tabTitle}>{_.toUpper(strings("main.theatres"))}</Text>
<ListTheatre navigation={this.props.navigation} filterText={this.state.filterText} isLoggedIn={this.state.isLoggedIn} fbPermissions={this.state.fbPermissions}></ListTheatre>
</View>
</ScrollableTabView>
</Container>
)
}
}
const mapStateToProps = (state) => {
return {
isLoggedIn: state.isLoggedIn,
listTheatre: state.listTheatre,
listMusic: state.listMusic
};
};
// wraps dispatch to create nicer functions to call within our component
const mapDispatchToProps = (dispatch) => ({
startup: () => dispatch(StartupActions.startup()),
loggedIn: () => dispatch({
type: LOGGED_IN
}),
fbPermissionsLoaded: (data) => dispatch({
type: FB_PERMISSIONS_LOADED,
fbPermissions: data
})
});
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen)
这是 child:
... imports
class ListTheatre extends Component {
constructor(props) {
super(props);
this.state = {
...
}
}
componentWillReceiveProps(nextProps) {
log(this.props)
}
shouldComponentUpdate(nextProps, nextState) {
return !nextState.fetching;
}
render() {
const { navigate } = this.props.navigation;
return (
<SectionList
...
/>
)
}
}
ListTheatre.propTypes = {
isLoggedIn: PropTypes.bool.isRequired,
}
const mapStateToProps = (state) => {
return {
isLoggedIn: state.isLoggedIn
};
};
const mapDispatchToProps = (dispatch) => ({
startup: () => dispatch(StartupActions.startup())
});
export default connect(mapStateToProps, mapDispatchToProps)(ListTheatre);
我不明白为什么 GraphRequestManager().addRequest
调用后的 setState 工作得很好(child 的 componentWillReceiveProps 函数被触发),而 dispatchFbPermissionAction 函数中的 setState 没有触发 componentWillReceiveProps child.
这是由于 connect
/Connect(ListTheatre)
包装了您的 ListTheatre 组件实现的 sCU(shouldComponentUpdate) 内部 为您关闭它,通过设置 pure 将其关闭连接到 false like
export default connect(mapStateToProps, mapDispatchToProps, null, {pure: false})(ListTheatre)
[pure] (Boolean): If true, connect() will avoid re-renders and calls to mapStateToProps, mapDispatchToProps, and mergeProps if the relevant state/props objects remain equal based on their respective equality checks. Assumes that the wrapped component is a “pure” component and does not rely on any input or state other than its props and the selected Redux store’s state. Default value: true