我目前正在处理某款应用,虽然我遇到的问题与此处相同,Updating Redux state does not trigger 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);
&#13;
我希望其他人之前见过类似的东西。感谢您提供任何帮助。
编辑:很遗憾,我还没有能够解决这个问题。但是在使用Redux调试器时我发现了一些非常有趣的东西。在调度动作后调用componentWillReceiveProps然后跳过&#39;跳过&#39;那个动作。看起来很奇怪,但至少它是一些东西。是时候继续挖掘了。
答案 0 :(得分:3)
connect
将浅显比较mapStateToProps
的输出与mapStateToProps
的上一输出。如果没有更改,则不会重新呈现连接的组件,即InformationScreen
。正如你所说的那样“肯定会改变状态”,浅层比较会发现mapStateToProps
的输出没有区别。
您可以通过传递正确的选项来覆盖避免重新渲染的这种行为。 connect
接受options
作为第4个参数,这是您需要设置pure: false
的对象。
[pure](Boolean):如果为true,则connect()将避免重新渲染并调用mapStateToProps,mapDispatchToProps和mergeProps,如果相关的state / props对象基于各自的相等性检查保持相等。假设包装组件是一个“纯”组件,并且不依赖于其道具和所选Redux商店状态之外的任何输入或状态。默认值:true
答案 1 :(得分:1)
你的reducer应该只返回一个代表状态的新对象(不改变当前状态)。 你的减速机应该是这样的
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
)的测试。事情是,对象看起来如何,它具有什么属性等无关紧要。只有被检查的东西是对象引用是否相同
答案 2 :(得分:0)
真正的问题在于:
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');
}
您正在修改现有标记对象,并调度操作以将其放入商店。 reducer只返回给定的标记对象。
我们始终强调 reducer 需要是可以不可更新地更新数据的纯函数,但实际上您需要创建新数据无论您在何处创建它。如果你的减速器只有return action.someValue
,那么创建的逻辑 someValue
需要不可改变地创建它。
因此,对于您的情况,您的markerPressed()
类方法需要对标记进行复制并为其指定新的坐标值。
答案 3 :(得分:0)
哇!我很高兴地说这个问题已得到解决。似乎原因在于,由于InformationScreen位于StackNavigator中,因此每次都会创建一个新实例。从第一次创建对象时,不会调用componentWillReceiveProps,这就解释了它。另外T 感谢@markerikson,指出我应该为每个动作调度重新创建一个标记对象。再次感谢,很高兴能够重新开始工作!这可能是一个菜鸟错误。
参考:https://shripadk.github.io/react/tips/componentWillReceiveProps-not-triggered-after-mounting.html