繁体   English   中英

更新Redux状态不会调用componentWillReceiveProps

[英]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

请参阅https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options

[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道具的严格相等性( === )。 问题是对象的外观如何,具有的属性等等都无关紧要。唯一要检查的是对象引用是否相同

https://redux.js.org/basics/reducers#handling-actions

https://redux.js.org/basics/reducers#note-on-object.assign

真正的问题在这里:

 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM