store.dispatch在从类外调用时未更新道具



store.js

import AsyncStorage from "@react-native-community/async-storage";
import { createStore, applyMiddleware } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import { createLogger } from "redux-logger";
import thunk from "redux-thunk";
import reducers from "../reducers";
const logger = createLogger({
// ...options
});
const persistedReducer = persistReducer(persistConfig, reducers);
export default () => {
let store = createStore(persistedReducer, {}, applyMiddleware(thunk, logger));
let persistor = persistStore(store);
return { store, persistor };
};

路径探索选项卡.js

import * as React from "react";
import {
View,
StyleSheet,
Text,
Dimensions,
TouchableOpacity,
Alert,
Platform,
Image
} from "react-native";
import { TabView, SceneMap, TabBar } from "react-native-tab-view";
import { Config } from "@common";
import { connect } from "react-redux";
import { compose } from "redux";
import { Dropdown } from "react-native-material-dropdown";
import { Field, reduxForm } from "redux-form";
import { ScrollView } from "react-native-gesture-handler";
import { Actions } from "react-native-router-flux";
import Icon from "react-native-vector-icons/Feather";
import {
searchImmipaths,
isKeepData,
backToInitialState,
continueFromPrevious,
fetchDynamicFacts,
pathExplorerTutorial
} from "../actions/path.actions";
import { checkConnection } from "../service/checkConnection";
import Loader from "./Loader";
import { colors, normalize, family, Images } from "@common";
import ResponsiveImage from 'react-native-responsive-image';
import { RFValue } from "react-native-responsive-fontsize";
import RNPicker from "rn-modal-picker";
import * as Animatable from 'react-native-animatable';
import UserinfoPopUp from "./../pages/UserinfoPopUp";
import { updateUserDetails, getUserDetails } from "../actions/auth.actions";
import AsyncStorage from "@react-native-community/async-storage";
import { copilot, walkthroughable, CopilotStep } from 'react-native-copilot';
import { StepNumberComponent } from "./../pages/newProfileScreen";
import persist from "./../config/store";
import Reactotron from 'reactotron-react-native'
const WalkthroughableImage = walkthroughable(Image);
const WalkthroughableText = walkthroughable(Text);
const WalkthroughableView = walkthroughable(View);
const WalkthroughableTouch = walkthroughable(TouchableOpacity);
const persistStore = persist();
const TooltipComponent = ({
isFirstStep,
isLastStep,
handleNext,
handlePrev,
handleStop,
labels,
currentStep,
}) => {
const handleDiscardTutorial = () => {
Alert.alert(
'',
'are you sure you don’t want a tutorial on how to use the app?',
[
{
text: 'yes',
onPress: () => {AsyncStorage.setItem('DontShowTutorial', JSON.stringify(true)), handleStop()}
},
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel'
},
],
{ cancelable: false }
);
}
return (
<View style={styles.tooltipContainer}>
<Text testID="stepDescription" style={styles.tooltipText}>{currentStep.text}</Text>
<View style={[styles.bottomBar]}>
{
!isFirstStep ?
<TouchableOpacity style={styles.toolTipButton} onPress={handlePrev}>
<Text style={styles.toolTipButtonText}>{'Previous'}</Text>
</TouchableOpacity>
: null
}
{
!isLastStep ?
<TouchableOpacity style={styles.toolTipButton} onPress={handleNext}>
<Text style={styles.toolTipButtonText}>{'Next'}</Text>
</TouchableOpacity> :
<TouchableOpacity style={styles.toolTipButton} onPress={handleStop}>
<Text style={styles.toolTipButtonText}>{'Finish'}</Text>
</TouchableOpacity>
}
<TouchableOpacity onPress={() => persistStore.store.dispatch(pathExplorerTutorial('bbv'))}>
<Text style={styles.toolTipButtonText}>Go</Text>
</TouchableOpacity>
<TouchableOpacity onPress={handleDiscardTutorial}>
<Text style={styles.toolTipButtonText}>Do not show tutorial</Text>
</TouchableOpacity>
</View>
</View>
);
}
const window = Dimensions.get("window");
var width = window.width;
var height = window.height;
var immigrationInterst = [];
var countryIntrest = [];
let countryIntrestNow = [];
var FirstRoute = () => <View style={[{ height: height }]} />;
let disableButton = false;
var lastSearchedCountries = [];
var SecondRoute = () => <View style={[{ height: height }]} />;
class PathexploredTab extends React.Component {
constructor(props) {
super(props);
this.imageMap = ['', Images.studyImage, Images.workImage, Images.residencyImage, Images.tourismImage];
this.state = {
isloading: false,
buttonone: false,
immibut1: false,
immibut2: false,
immibut3: false,
immibut4: false,
userInfoPopUpVisible: false, 
countrybut1: false,
countrybut2: false,
countrybut3: false,
countrybut4: false,
filedsToShow: [],
countrybut5: false,
countrybut6: false,
selectedval: "Select the Country",
index: 0,
routes: [
{ key: "first", title: "Select Goals" },
{ key: "second", title: "Select Countries" }
],
checkconnection: false,
errorMessage: "",
isItemSelected: true,
currentlySelectedItemIndex: -1,
isItemChecked: true,
checkboxData: ""
};
}
componentDidUpdate = (nextProps) => {
Reactotron.log('=====', nextProps.userPressedGo)
}
componentWillReceiveProps = (nextProps) => {

}
componentWillMount = async() => {
const {
getUser: { userDetails },
authData: { token }
} = this.props;
this.props.dispatch(getUserDetails(userDetails.userid, token))
}
componentDidMount() {
setTimeout(() => {
this.props.start();
}, 1000);
immigrationInterst = [];
countryIntrest = [];
countryIntrestNow = [];
const {
getUser: { userDetails }
} = this.props;


}


callProceed = () => {
const {
isItemSelected,
currentlySelectedItemIndex,
isItemChecked
} = this.state;
if (isItemSelected) {
Alert.alert("Immigreat", "Please select any goal");
return;
}
const lastGoal = this.props.immigationInterest[0]
//This is a bit of a hacky fix but it works.
let allPrevCountriesFound = lastSearchedCountries.every(ai => countryIntrestNow.includes(ai))
&& (lastSearchedCountries.length == countryIntrestNow.length);
//We want to clear and search when:
//a) There is no exploration id
//b) Even if there is an exploration id but the lastGoal or last countries dont match
//Note: We make one exception for if exploration id exists but the lastSearchedCountries is just an empty list
let noExplorationId = (this.props.explorationId === "");
let countryGoalDontMatch = (lastGoal != currentlySelectedItemIndex || !allPrevCountriesFound);
let isProceedException = (lastSearchedCountries.length == 0 && !noExplorationId);
noExplorationId || (!noExplorationId && countryGoalDontMatch && !isProceedException)
?
this.clearAndSearch()
: Alert.alert(
"Immigreat",
"Previous exploration found. Would you like to continue?",
[
{
text: "START FROM BEGINNING",
onPress: () => {
this.props.dispatch(continueFromPrevious(0));
this.props.dispatch(backToInitialState());
this.props.dispatch(isKeepData(false));
this._searchData();
},
style: "cancel"
},
{
text: "CONTINUE",
onPress: () => {
lastSearchedCountries = [...countryIntrest];
this.props.dispatch(isKeepData(true));
this.props.didTapOnSearch();
}
},
{
text: "Cancel",
onPress: () => console.log("Canceled"),
style: "cancel"
}
],
{ cancelable: false }
);
}



_onPressBackButton = () => {
this.setState(
{
isItemSelected: true,
currentlySelectedItemIndex: -1,
isItemChecked: false
},
() => {
setTimeout(() => {
this.intialLoadValues();
//this.setState({ isItemSelected: true });
}, 0);
}
);
}
extraOptionsRefresh() {
const { currentlySelectedItemIndex, isItemChecked } = this.state;
this.setState({ isItemChecked: !isItemChecked })
switch (currentlySelectedItemIndex) {
case 1:
this.setState({checkBoxData:
"Do you want to explore options you may have after your studies?"});
break;
case 2:
this.setState({checkBoxData: 
"Do you want to explore other goal options (such as studies) that can lead to work options?"});
break;
case 3:
this.setState({checkBoxData:
"Do you want to explore other goal options (such as studies or work) that could lead to permanent residency in the future?"});
break;
case -1:
this.setState({checkBoxData: ""});
break;
}
}
intialLoadValues() {
const { currentlySelectedItemIndex, isItemChecked } = this.state;
/*var checkBoxData = "";
switch (currentlySelectedItemIndex) {
case 1:
checkBoxData =
"Do you want to explore options you may have after your studies?";
break;
case 2:
checkBoxData = "Do you want to explore other goal options (such as studies) that can lead to work options?";
break;
case 3:
checkBoxData =
"Do you want to explore other goal options (such as studies or work) that could lead to permanent residency in the future?";
break;
case 4:
checkBoxData = "";
break;
}*/
FirstRoute = () => (
<ScrollView style={{ flex: 1, backgroundColor: "white" }}>
<Animatable.View animation="fadeIn" duration={1200} style={{ flex: 1 }}>
<View
style={{
backgroundColor: "#DBDDDF",
alignItems: "center",
justifyContent: "center",
flex: 1
}}
>
<View style={{ padding: 20 }}>
<Text
style={{
textAlign: "center",
fontFamily: "SourceSansPro-Semibold",
color: "#2C393F",
fontSize: RFValue(12)
}}
>
Select the Immigration goal that you would be interested in
exploring
</Text>
<Text
style={{
textAlign: "center",
color: "#008BC7",
fontFamily: "SourceSansPro-Regular",
fontSize: RFValue(10)
}}
>
You can select/deselect ONLY one goal at a time by clicking the buttons. This is so we can help you hone your search!
</Text>
</View>
</View>
{(this.state.isItemSelected && this.state.currentlySelectedItemIndex < 0) ? (
<View style={{ marginTop: 30 }}>
{/*<Animatable.View animation="fadeIn" duration={1200} style={{ flexGrow: 1, justifyContent: 'center', alignItems: 'center', flexDirection: 'row' }}>*/}
<View style={styles.custombuttonView}>
<View style={{ width: "50%" }}>
<CopilotStep text="Select Your goals" order={1} name="study">
<WalkthroughableTouch
testID={`${Config.immigerat[0].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[0].code)
}
style={
this.state.immibut1
? styles.selectedbutton
: styles.buttonstyleview
}
>
<WalkthroughableText
style={
this.state.immibut1
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[0].value}
</WalkthroughableText>
</WalkthroughableTouch>
</CopilotStep>
</View>
<View style={{ width: "50%" }}>
<TouchableOpacity
testID={`${Config.immigerat[1].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[1].code)
}
style={
this.state.immibut2
? styles.selectedbutton
: styles.buttonstyleview
}
>
<Text
style={
this.state.immibut2
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[1].value}
</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.custombuttonView}>
<View style={{ width: "50%" }}>
<TouchableOpacity
testID={`${Config.immigerat[2].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[2].code)
}
style={
this.state.immibut3
? styles.selectedbutton
: styles.buttonstyleview
}
>
<Text
style={
this.state.immibut3
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[2].value}
</Text>
</TouchableOpacity>
</View>
<View style={{ width: "50%" }}>
<TouchableOpacity
testID={`${Config.immigerat[3].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[3].code)
}
style={
this.state.immibut4
? styles.selectedbutton
: styles.buttonstyleview
}
>
<Text
style={
this.state.immibut4
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[3].value}
</Text>
</TouchableOpacity>
</View>
</View>
{/*</Animatable.View>*/}
</View>
) : (
<View style={{ flex: 0.75, marginTop: 30 }}>
{/*<Animatable.View animation="fadeIn" duration={1200}>*/}
<View style={{ flexDirection: 'row', alignContent: 'center' }}>
<TouchableOpacity testID='goBackButton'
onPress={this._onPressBackButton} style={{ padding: 10 }} >
<View style={{ width: 80 }}>
<Icon name="chevron-left" size={30} color="black" />
</View>
</TouchableOpacity>
{<TouchableOpacity
onPress={() => this._immigreateIntrest("null")}
style={[styles.selectedbutton, { width: "50%" }]}
>
<Text style={styles.selectedbuttontext}>
{Config.immigerat[this.state.currentlySelectedItemIndex - 1].value}
</Text>
</TouchableOpacity>}
</View>
{currentlySelectedItemIndex !== 4 && (
<View
style={{
borderWidth: 1,
borderRadius: 3,
borderColor: "rgba(110,110,110,0.4)",
flex: 1,
marginHorizontal: 10,
marginTop: 30,
flexDirection: "row"
}}
>
<TouchableOpacity
activeOpacity={0.8}
onPress={() => {
this.extraOptionsRefresh()
//setTimeout(() => {
//this.extraOptionsRefresh();
//this.intialLoadValues();
//this.setState({ isItemChecked: !isItemChecked });
//}, 100);
}
}
style={{
// flex: 0.35,
alignItems: "center",
justifyContent: "center",
marginLeft: 15
}}
hitSlop={{ top: 20, bottom: 20, left: 50, right: 50 }}
>
<View
style={[
styles.button,
{
backgroundColor: "white",
borderColor: "rgba(110,110,110,0.4)",
borderWidth: 1,
borderRadius: 2,
width: 20,
height: 20
}
]}
>
{this.state.isItemChecked ? (
<Icon name={"check"} color={colors.LIGHT_BLUE} size={15} />
) : null}
</View>
</TouchableOpacity>
<Text
style={{
flex: 1,
marginVertical: 10,
marginLeft: 10,
fontFamily: "SourceSansPro-Bold",
color: "#242424",
fontSize: RFValue(12)
}}
>
{this.state.checkBoxData}
</Text>
</View>
)}
{(!this.state.isItemSelected && this.state.currentlySelectedItemIndex > 0) &&
<Animatable.View animation="fadeIn" duration={1200} style={{ flexGrow: 1, justifyContent: 'center', alignItems: 'center', flexDirection: 'row' }}>
<ResponsiveImage source={this.imageMap[this.state.currentlySelectedItemIndex]} initWidth="270" initHeight="220" />
</Animatable.View>
}
</View>
)}
<View>
<TouchableOpacity
testID='searchButton'
onPress={() => !disableButton && this.showAlert1()}
style={{
width: 130,
justifyContent: "center",
backgroundColor: colors.LIGHT_BLUE,
borderRadius: 100,
padding: 10,
alignSelf: "center",
marginTop: height > 700 ? 60 : 40,
marginBottom: 20
}}
>
<Text
style={{
textAlign: "center",
color: "#fff",
fontFamily: "SourceSansPro-Regular"
}}
>
Search
</Text>
</TouchableOpacity>
</View>
</Animatable.View>
</ScrollView>
);
SecondRoute = () => (
<ScrollView style={{ flex: 1, backgroundColor: "white" }}>
<View style={{ backgroundColor: "white" }}>
<View
style={{
alignSelf: "center",
justifyContent: "center",
width: width
}}
>
<View style={{ margin: 20, alignSelf: "center" }}>
<Text
style={{
textAlign: "center",
fontFamily: "SourceSansPro-Semibold",
color: "#2C393F",
fontSize: 15
}}
>
Select all countries you are keen to explore
</Text>
<Text
style={{
textAlign: "center",
color: "rgba(44, 57, 63,0.6)",
marginTop: 20,
fontFamily: "SourceSansPro-Semibold"
}}
>
From:
</Text>
<View style={styles.loginView}>
<Field
name="selectcountry"
placeholder={this.state.selectedval}
component={this.renderDropdown}
data={Config.countries}
/>
</View>
<Text
style={{
textAlign: "center",
color: "rgba(44, 57, 63,0.6)",
marginTop: 20,
fontFamily: "SourceSansPro-Semibold"
}}
>
To:
</Text>
</View>
</View>
<View>
<View style={styles.custombuttonView}>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[0].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[0].code)
}
>
<Image
style={styles.countryIcon}
source={this.state.countrybut1
? Images.usa_selected
: Images.usa_unavailable}
/>
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[1].value + 'interestButton'}`}

>
<Image
style={styles.countryIcon}
source={this.state.countrybut2
? Images.canada_selected
: Images.canada_unavailable}
/>
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[2].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[2].code)
}
>
<Image

</TouchableOpacity>
</View>
</View>
<View style={styles.custombuttonView}>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[3].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[3].code)
}
>
<Image

/>
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[4].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[4].code)
}
>
<Image

</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[5].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[5].code)
}
>
<Image

/>
</TouchableOpacity>
</View>
</View>
</View>
<View>
<TouchableOpacity
testID='countrySearchButton'
onPress={() => !disableButton && this.showAlert1()}
style={{

}}
>
<Text

>
Search
</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
);
}
_countryIntrest(code) {
// alert(code);
var index = countryIntrest.indexOf(code);
var butstr = "countrybut" + code;
if (index == -1) {
countryIntrest.push(code);
countryIntrestNow.push(code);
this.setState({ [butstr]: true });
this.intialLoadValues();
} else {
countryIntrest.splice(index, 1);
countryIntrestNow.splice(index, 1);
this.setState({ [butstr]: false });
this.intialLoadValues();
}
}
_immigreateIntrest = async(code) => {
if(code === 4){
)
return;
}
const { isItemSelected } = this.state;
if (code === "null") {


);
} else {
await this.setState(

);
}
}
renderScene = ({ route }) => {
switch (route.key) {
case 'first':

case 'second':

default:
return null;
}
};
render() {
return (
<View style={{ flex: 1 }}>
{this.props.isLoading && (
<View
style={{

}}
>
<Loader />
</View>
)}
<TabView
removeClippedSubviews={Platform.OS === "android" ? true : false}
style={{
backgroundColor: this.state.index === 0 ? "#DBDDDF" : "white"
}}
navigationState={this.state}
removeClippedSubviews={Platform.OS === "android" ? true : false}
renderTabBar={props => (
<TabBar

}}


pass
getLabelText={({ route }) => route.title}
/>
)}
/>
<UserinfoPopUp
visible={this.state.userInfoPopUpVisible}
onClose={()=>this.setState({ userInfoPopUpVisible: false })}
userPopUpSubmit={this._userPopUpSubmit.bind(this)}
/>
</View>
);
}
}
mapStateToProps = state => ({
userPressedGo: state.pathReducer.getImmipathDetails.userPressedGo,
});
mapDispatchToProps = dispatch => ({
dispatch
});
export default compose(
connect(
mapStateToProps,
mapDispatchToProps
),
reduxForm({
form: "pathexplorertab"
// validate
})
)(copilot({
tooltipComponent: TooltipComponent,
stepNumberComponent: StepNumberComponent
})(PathexploredTab));

Pathexplorer.js包含Pathexplorer类,其中有一个名为ToolTipComponent的组件,我从中调用操作,但该操作没有反映在mapStateToProps中。我被迫这样做的原因是,我使用了一个名为react native copilot的库,其中我有一个自定义的工具提示组件,我想从中访问状态

此事件中的问题:

onPress={store.dispatch(action)}

应该是:

onPress={()=>store.dispatch(action)}

顺便说一下,你可以连接你的功能组件,比如类组件:

export default connect(
mapStateToProps,
mapDispatchToProps
)
)(TooltipComponent)

最新更新