[英]componentWillReceiveProps method doesn't run anymore when using redux to call api
[英]Updating redux state doesn't call componentWillReceiveProps
目前,我正在开发一个应用程序,尽管我面临与此处相同的问题,但更新Redux状态不会触发componentWillReceiveProps 。
我已经阅读了这个答案,并且没有改变状态,登录mapStateToProps时可以看到不同的状态,但是我的componentWillReceiveProps没有被触发。
我的代码如下:
const mapReducer = (state = {}, action) => { switch (action.type) { case 'SET_MARKER': return action.selectedMarker; default: return state } } export default mapReducer //mapActions.js export const setMarker = (selectedMarker) => { //Used to set the one that the user has selected. return { type: 'SET_MARKER', selectedMarker } } //InformationScreen.js const mapStateToProps = (state) => { console.log('returning in mapStateToProps'); console.log(state.mapReducer); //Here I see that state.mapReducer is different everytime. return { marker: state.mapReducer, user: state.userReducer, completed: state.completedReducer } } class InformationScreen extends React.Component { componentWillReceiveProps(nextProps) { //No logs in here. console.log('Receiving props and the marker is'); console.log(nextProps.marker); } render() { const { marker } = this.props; console.log(marker); // Here the marker does update. return(<Text> Hello world </Text>); } } export default connect(mapStateToProps)(InformationScreen); import app from './reducers'; let store = createStore(app); export default class App extends React.Component { state = { isLoadingComplete: false, }; render() { if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) { return ( <AppLoading startAsync={this._loadResourcesAsync} onError={this._handleLoadingError} onFinish={this._handleFinishLoading} /> ); } else { return ( <ActionSheetProvider> <Provider store={store}> <View style={styles.container}> {Platform.OS === 'ios' && <StatusBar barStyle="default" />} {Platform.OS === 'android' && <View style={styles.statusBarUnderlay} />} <RootNavigation /> </View> </Provider> </ActionSheetProvider> ); } } } //index.js import { combineReducers } from 'redux' import mapReducer from './mapReducer' const app = combineReducers({ mapReducer, //other reducers }) export default app //Dispatching the action from import { connect } from 'react-redux'; import { setMarker } from '../actions/mapActions'; import { Container, Header, Tab, Tabs, TabHeading, List, ListItem, Left, Thumbnail, Body, Separator, Badge, Right} from 'native-base'; import _ from 'lodash'; import GLOBALS from '../constants/Globals'; const mapStateToProps = (state) => { return { user: state.userReducer, challenges: state.allChallengesReducer } } class MyChallengesScreen extends React.Component { static navigationOptions = { title: 'My Challenges', headerTintColor: 'rgb(255, 255, 255)', headerStyle: { backgroundColor: 'rgba(77, 90, 139, 1)'} }; componentDidMount() { this.handleRefresh(); } componentWillReceiveProps(nextProps) { if (nextProps.user.facebookId) { this.handleRefresh(nextProps); } } constructor (props) { super(props); this.state = { refreshing: false, } } markerPressed = (marker) => { //setChallenge. marker.coordinate = {latitude : +marker.latitude, longitude: +marker.longitude}; console.log('Setting the marker'); this.props.dispatch(setMarker(marker)); this.props.navigation.navigate('InformationScreen'); } render() { return ( <Button onPress={() => this.markerPressed()}></Button> ) } } export default connect(mapStateToProps)(MarkersScreen);
我希望其他人以前也看到过类似的东西。 感谢您提供的建议。
编辑:因此很遗憾,我仍然无法解决此问题。 但是使用Redux调试器时,我发现了一些非常有趣的东西。 在分派动作之后,我将“跳过”该动作,然后调用componentWillReceiveProps。 似乎很奇怪,但至少是这样。 是时候继续挖掘了。
connect
将浅的输出比较mapStateToProps
到以前的输出mapStateToProps
。 如果没有更改,它将不会重新渲染连接的组件,即InformationScreen
。 正如您所说的,您是“绝对地改变状态”,浅表比较不会发现mapStateToProps
的输出之间存在差异。
您可以通过传入正确的选项来覆盖避免重新渲染的行为。 connect
接受options
作为第四个参数,这是您需要为其设置pure: false
。
[pure](布尔值):如果为true,则connect()将避免重新渲染并在相关状态/道具对象根据其各自的相等性检查保持相等的情况下调用mapStateToProps,mapDispatchToProps和mergeProps。 假定包装的组件是“纯”组件,除了其道具和所选Redux存储的状态外,不依赖于任何输入或状态。 默认值:true
减速器应仅返回表示状态的新对象(而不更改当前状态)。 您的减速器应如下所示
const mapReducer = (state = {selectedMarker: null}, action) => {
switch (action.type) {
case 'SET_MARKER':
return Object.assign({}, state, {
selectedMarker: action.selectedMarker
});
default:
return state
}
}
Object.assign
通过添加之后所有参数中存在的所有属性来对第一个参数进行突变。 意味着它将通过首先添加处于state
的属性,然后添加属性selectedMarker: action.selectedMarker
使{}
突变。 如果state
已经具有selectedMarker
则它将在新对象中被覆盖。
并在您的mapStateToProps
const mapStateToProps = (state) => {
return {
marker: state.mapReducer.selectedMarker,
...
}
}
对象突变在mapStateToProps
之后,控制台日志显示不同的值。问题是您无法直观地看出它是否是一个突变的对象。 connect
中发生的事情是测试了新的marker
道具与先前的marker
道具的严格相等性( ===
)。 问题是对象的外观如何,具有的属性等等都无关紧要。唯一要检查的是对象引用是否相同
真正的问题在这里:
markerPressed = (marker) => {
//setChallenge.
marker.coordinate = {latitude : +marker.latitude, longitude: +marker.longitude};
console.log('Setting the marker');
this.props.dispatch(setMarker(marker));
this.props.navigation.navigate('InformationScreen');
}
您正在修改现有的标记对象,并调度一个操作以将其放入商店。 减速器只返回给定的标记对象。
我们始终强调, reduces必须是能够不变地更新数据的纯函数,但实际上, 无论在哪里创建新数据,您实际上都需要不变地创建新数据。 如果您有一个reducer只return action.someValue
,则创建 someValue
的逻辑需要不变地创建它。
因此,对于您的情况,您的markerPressed()
类方法需要制作一个标记的副本并为其指定新的坐标值。
哇! 我很高兴地说这个问题已经解决。 似乎原因在于,由于InformationScreen位于StackNavigator中,因此每次都会创建一个新实例。 由于第一次创建对象时未调用componentWillReceiveProps,因此对此进行了解释。 另外,感谢@markerikson,他指出我应该在每次动作分派时重新创建一个标记对象。 再次感谢您,很高兴能够重新开始工作! 这可能是菜鸟的错误。
参考: https : //shripadk.github.io/react/tips/componentWillReceiveProps-not-triggered-after-mounting.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.