I created a custom ModalContext.js but my test modal does not seem to be showing when I trigger a button's onPress
// ModalContext.js
import createDataContext from './createDataContext';
const modalReducer = (state, action) => {
switch (action.type) {
case 'openModal':
return { ...state, component: action.payload };
case 'hideModal':
return { ...state, component: null };
default:
return state;
}
};
const openModal = (dispatch) => (component) => {
console.log('hey there');
dispatch({ type: 'openModal', payload: component });
};
const hideModal = (dispatch) => () => {
dispatch({ type: 'hideModal' });
};
export const { Provider, Context } = createDataContext(
modalReducer,
{
openModal,
hideModal,
},
{ component: null }
);
// createDataContext.js
import React, { useReducer } from 'react';
export default (reducer, actions, defaultValue) => {
const Context = React.createContext();
const Provider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, defaultValue);
const boundActions = {};
for (let key in actions) {
boundActions[key] = actions[key](dispatch);
}
return (
<Context.Provider value={{ state, ...boundActions }}>
{children}
</Context.Provider>
);
};
return { Context, Provider };
};
// App.js
const App = createAppContainer(navigator);
export default () => {
return (
<ModalProvider>
<AuthProvider>
<App
ref={(navigator) => {
setNavigator(navigator);
}}
/>
</AuthProvider>
</ModalProvider>
);
};
I have a button on a test screen to check if it works or not.
// WebViewScreen.js
import React, { useState, useContext } from 'react';
import { StyleSheet, Modal, View, Text, Button } from 'react-native';
import { Context as ModalContext } from '../context/ModalContext';
const WebViewScreen = ({ navigation }) => {
const { state, openModal } = useContext(ModalContext);
const errorModal = (
<View>
<Modal animationType='slide' visible={true}>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text>Hello</Text>
</View>
</View>
</Modal>
</View>
);
return (
<>
<Button
onPress={() => {
openModal(errorModal);
}}
title='button'
/>
</>
);
};
WebViewScreen.navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('title'),
};
};
const styles = StyleSheet.create({
view: {
backgroundColor: '#f1f3f4',
},
centeredView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginTop: 22,
},
modalView: {
margin: 20,
backgroundColor: 'white',
borderRadius: 20,
padding: 35,
alignItems: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5,
},
});
export default WebViewScreen;
It seems to actually call the function as I can see "hey there" on the console but no modals appear.
I am not sure this is what you are looking for or not but I manage my details like following.
class Abc {
var1;
var2;
var3 = new B();
var4 = new C();
var5 = {}
var6 = [];
success = a => {
//your logic
}
}
class B {
varA;
varB;
varC = false;
}
I hope this is helpful.
Related
I am using redux persist with asyncstorage save items in a bookmarks list. The items are in a flatlist and when I click on one item, it navigates me to another screen. I would like to implement the functional bookmark in the header of that screen.
When I tried doing this, and clicked the bookmark in the header, and go back to the bookmarks, it just shows a blank card. It looks like it is not updating the state properly. How can I fix this?
StackNavigator.tsx
const MainStackNavigator = () => {
const { books, bookmarks } = useAppSelector((state) => state.booksReducer);
const dispatch = useDispatch();
const fetchBooks = () => dispatch(getBooks());
const addToBookmarkList = (book) => dispatch(addBookmark(book));
const removeFromBookmarkList = (book) => dispatch(removeBookmark(book));
useEffect(() => {
fetchBooks();
}, []);
const handleAddBookmark = (book) => {
addToBookmarkList(book);
};
const handleRemoveBookmark = (book) => {
removeFromBookmarkList(book);
};
const handleSwapBookmark = (book) => {
removeFromBookmarkList(book);
};
const RenderItem = () => {
const ifExists = (book) => {
if (bookmarks.filter((item) => item.id === book.id).length > 0) {
return true;
}
return false;
};
return (
<TouchableOpacity
onPress={() =>
ifExists(i) ? handleRemoveBookmark(i) : handleAddBookmark(i)
}
activeOpacity={0.7}
style={{
flexDirection: "row",
padding: 2,
backgroundColor: ifExists(i) ? "#F96D41" : "#2D3038",
borderRadius: 20,
alignItems: "center",
justifyContent: "center",
height: 40,
width: 40,
}}
>
<MaterialCommunityIcons
color={ifExists(i) ? "white" : "#64676D"}
size={24}
name={ifExists(i) ? "bookmark-outline" : "bookmark"}
/>
</TouchableOpacity>
);
};
return (
<AppStack.Navigator>
<AppStack.Screen
name="BookmarksScreen"
component={BookmarksScreen}
options={{
title: "Search",
statusBarColor: isDarkMode ? "white" : "black",
headerLargeTitle: true,
headerTranslucent: true,
headerLargeTitleHideShadow: true,
}}
/>
<AppStack.Screen
name="Screen2"
component={Screen2}
options={({ route }) => ({
headerLargeTitle: false,
title: route.params.name,
headerTranslucent: true,
headerRight: () => <RenderItem item={route.params.name} />,
})}
/>
</AppStack.Navigator>
);
};
actions.js
import axios from "axios";
import { BASE_URL } from "../config";
// Define action types
export const GET_BOOKS = "GET_BOOKS";
export const ADD_TO_BOOKMARK_LIST = "ADD_TO_BOOKMARK_LIST";
export const REMOVE_FROM_BOOKMARK_LIST = "REMOVE_FROM_BOOKMARK_LIST";
export const SWAP_IN_BOOKMARK_LIST = "SWAP_IN_BOOKMARK_LIST";
export const getBooks = () => {
try {
return async (dispatch) => {
const response = await axios.get(`${BASE_URL}`);
if (response.data) {
dispatch({
type: GET_BOOKS,
payload: response.data,
});
} else {
console.log("Unable to fetch data from the API BASE URL!");
}
};
} catch (error) {
console.log(error);
}
};
export const addBookmark = (book) => (dispatch) => {
dispatch({
type: ADD_TO_BOOKMARK_LIST,
payload: book,
});
};
export const removeBookmark = (book) => (dispatch) => {
dispatch({
type: REMOVE_FROM_BOOKMARK_LIST,
payload: book,
});
};
hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store";
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
reducers.ts
import {
GET_BOOKS,
ADD_TO_BOOKMARK_LIST,
REMOVE_FROM_BOOKMARK_LIST,
} from "./actions";
const initialState = {
books: [],
bookmarks: [],
};
function booksReducer(state = initialState, action) {
switch (action.type) {
case GET_BOOKS:
return { ...state, books: action.payload };
case ADD_TO_BOOKMARK_LIST:
return { ...state, bookmarks: [...state.bookmarks, action.payload] };
case REMOVE_FROM_BOOKMARK_LIST:
return {
...state,
bookmarks: state.bookmarks.filter(
(book) => book.id !== action.payload.id
),
};
default:
return state;
}
}
export default booksReducer;
store.ts
import { createStore, combineReducers, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import AsyncStorage from "#react-native-async-storage/async-storage";
import { persistStore, persistReducer } from "redux-persist";
import booksReducer from "./reducers";
const persistConfig = {
key: "root",
storage: AsyncStorage,
whitelist: ["bookmarks"],
};
const rootReducer = combineReducers({
booksReducer: persistReducer(persistConfig, booksReducer),
});
export const store = createStore(rootReducer, applyMiddleware(thunk));
export const persistor = persistStore(store);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
BookmarksScreen.tsx
const BookmarksScreen = () => {
return (
<View>
<FlatList
data={bookmarks}
keyExtractor={(item) => item.id}
renderItem={renderItem}
showsVerticalScrollIndicator={false}
/>
</View>
);
}
renderItem
const renderItem = ({ item }) => {
return (
<TouchableOpacity
onPress={() =>
navigation.navigate("Screen2", {name: item.name})}
>
<View style={{ flexDirection: "row", flex: 1 }}>
<View>
<Text
style={{
fontSize: 22,
paddingRight: 16,
color: "black",
fontFamily: "Medium",
left: 45,
top: 6,
}}
>
{item.country}
</Text>
</View>
</View>
</View>
</TouchableOpacity>
);
};
I think you forgot to access props that's the reason booked-marked not working i change some code please check it's working or not.
StackNavigator.tsx
const RenderItem = (item) => {
const ifExists = (book) => {
if (bookmarks.filter((item) => item.id === book.id).length > 0) {
return true;
}
return false;
};
return (
<TouchableOpacity
onPress={() =>
ifExists(item) ? handleRemoveBookmark(item) : handleAddBookmark(item)
}
activeOpacity={0.7}
style={{
flexDirection: "row",
padding: 2,
backgroundColor: ifExists(i) ? "#F96D41" : "#2D3038",
borderRadius: 20,
alignItems: "center",
justifyContent: "center",
height: 40,
width: 40,
}}
>
<MaterialCommunityIcons
color={ifExists(i) ? "white" : "#64676D"}
size={24}
name={ifExists(i) ? "bookmark-outline" : "bookmark"}
/>
</TouchableOpacity>
);
};
Who can support on my issue: Dispatching an action does does change the state as anticipated. But the component from which the issue gets dispatched does not re-render. When I simply save the component, it of course re-renders and shows the desiree effekt.
Here my files:
actions.js
export const TOGGLE_PRODUCT = "TOGGLE_PRODUCT";
export const INCREMENT = "INCREMENT";
//ACTION CREATER FUNCTIONS
export const toggleProduct = (id) => {
return {
type: TOGGLE_PRODUCT,
productId: id,
};
};
reducer.js
import { PRODUCTLIST } from "../../data/dummydata";
import { TOGGLE_PRODUCT } from "../actions/products";
const initialState = {
allProducts: PRODUCTLIST,
};
const productReducer = (state = initialState, action) => {
switch (action.type) {
case TOGGLE_PRODUCT:
const Products = state.allProducts;
const toggledProduct = Products.find((el) => el.id === action.productId);
if (toggledProduct.status === false) {
toggledProduct.status = true;
} else {
toggledProduct.status = false;
}
console.log("Neue Products: ", Products);
return {
allProducts: Products,
};
default:
return state;
}
};
export default productReducer;
component.js
import { useSelector, useDispatch } from "react-redux";
import React, { useEffect, useCallback } from "react";
import { Text, View, Button, FlatList, StyleSheet } from "react-native";
import Product from "../components/Product";
import { toggleProduct } from "../store/actions/products";
import { increment } from "../store/actions/products";
const ShoppingListScreen = (props) => {
const dispatch = useDispatch();
const toggleProductHandler = useCallback(
// useCallback verhindert infinite loop
(id) => {
dispatch(toggleProduct(id));
},
[]
);
const Products = useSelector((state) => state.product.allProducts);
return (
<View style={styles.screen}>
<FlatList
data={Products}
renderItem={({ item }) => (
<View
style={
item.status === true ? styles.elementselected : styles.element
}
>
<Product
style={styles.text}
id={item.id}
product={item.product}
department={item.department}
status={item.status}
onClick={() => toggleProductHandler(item.id)}
/>
</View>
)}
/>
<View style={styles.button}>
<Button
title="FERTIG"
onPress={() => {
props.navigation.goBack();
}}
/>
{/* <Button
title='Stand "cartRewe" '
onPress={() => {
props.testFunction1();
}}
/>
<Button
title='Stand "planRewe" '
onPress={() => {
props.testFunction2();
}}
/> */}
</View>
</View>
);
};
const styles = StyleSheet.create({
screen: {
backgroundColor: "#fafafa",
flex: 1,
justifyContent: "flex-start",
},
element: {
backgroundColor: "#ddd",
borderWidth: 2,
borderColor: "#bbb",
borderRadius: 20,
marginVertical: 5,
marginHorizontal: 25,
},
elementselected: {
backgroundColor: "#a0ffa0",
borderWidth: 3,
borderColor: "#64ff64",
borderRadius: 20,
marginVertical: 5,
marginHorizontal: 25,
},
text: {
color: "#333",
// fontSize: 22,
// marginHorizontal: 10
},
button: {
marginVertical: 24,
},
});
export default ShoppingListScreen;
These lines are the problem:
const Products = state.allProducts;
const toggledProduct = Products.find((el) => el.id === action.productId);
if (toggledProduct.status === false) {
toggledProduct.status = true;
} else {
toggledProduct.status = false;
}
return {
allProducts: Products,
};
That's mutating the existing state, and you must never mutate the state in a Redux reducer!.
To fix this, you would need to make copies of the Products array and the toggledProduct object, update the copies, and return those.
Having said that, the better option is to use our official Redux Toolkit package, which is our recommended approach for writing Redux logic. It lets you write "mutating" logic that is turned into safe and correct immutable updates.
Here's what this would look like with Redux Toolkit's createSlice API:
const productsSlice = createSlice({
name: 'products',
initialState: {allProducts: []},
reducers: {
productToggled(state, action) {
const toggledProduct = state.allProducts.find(e => e.id === action.payload);
// This "mutating" syntax _only_ works inside Redux Toolkit's createSlice/createReducer!
toggledProduct.status = !toggledProduct.status;
}
}
})
This totally makes sense to not mutate the state object. Since I do now want to implement a further package just for this issue, I revised my source code as advised. For any reason my component still does not rerender without a manual safe. How about this code, what is still wrong?
reducer.js
import { PRODUCTLIST } from "../../data/dummydata";
import { TOGGLE_PRODUCT } from "../actions/products";
const initialState = {
allProducts: PRODUCTLIST,
};
const productReducer = (state = initialState, action) => {
switch (action.type) {
case TOGGLE_PRODUCT:
const newProducts = state.allProducts;
const toggledProduct = newProducts.findIndex(
(el, idx) => el.id === action.productId
);
if (newProducts[toggledProduct].status === false) {
newProducts[toggledProduct].status = true;
} else {
newProducts[toggledProduct].status = false;
}
return {
...state,
newProducts,
};
default:
return state;
}
};
export default productReducer;
Is there a way to hide components when the keyboard shows, aside from installing packages?
Using the code sample from the Keyboard documentation, I would do something like this:
class Example extends Component {
state = {keyboardOpen: false};
componentDidMount() {
this.keyboardDidShowListener = Keyboard.addListener(
'keyboardDidShow',
this._keyboardDidShow,
);
this.keyboardDidHideListener = Keyboard.addListener(
'keyboardDidHide',
this._keyboardDidHide,
);
}
componentWillUnmount() {
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
}
_keyboardDidShow() {
this.setState({
keyboardOpen: true
});
}
_keyboardDidHide() {
this.setState({
keyboardOpen: false
});
}
render() {
return (
{!this.state.keyboardOpen && <MyComponent />}
);
}
}
Basically, in componentDidMount you subscribe to the show and hide keyboard events. You keep track of the Keyboard current state in your Component state thanks to this.state.keyboardOpen and you conditionally display MyComponent based on the value of this.state.keyboardOpen in your render method.
For those using functional components, here is a hook that you could use to detect when the keyboard is opened and closed.
import { useEffect, useState, useMemo } from "react";
import { Keyboard } from "react-native";
const useKeyboardOpen = () => {
const [isKeyboardOpen, setIsKeyboardOpen] = useState(false);
useEffect(() => {
const keyboardOpenListener = Keyboard.addListener("keyboardDidShow", () =>
setIsKeyboardOpen(true)
);
const keyboardCloseListener = Keyboard.addListener("keyboardDidHide", () =>
setIsKeyboardOpen(false)
);
return () => {
if (keyboardOpenListener) keyboardOpenListener.remove();
if (keyboardCloseListener) keyboardCloseListener.remove();
};
}, []);
return isKeyboardOpen;
};
export default useKeyboardOpen;
And this is how I use it in my projects:
import { useTheme } from "react-native-paper";
import useKeyboardOpen from "hooks/useKeyboardOpen";
export const Login = () => {
const theme = useTheme();
const isKeyboardOpen = useKeyboardOpen();
const styles = useStyles(theme, isKeyboardOpen);
return (
<View style = {styles.container}>
<View style = {styles.logo}>
<Logo />
</View>
<View style = {styles.form}>
....
</View>
</View>
);
};
const useStyles = (theme, isKeyboardOpen) = (
StyleSheet.create({
container: {
flex: 1,
},
logo: {
flex: 1,
marginTop: 20,
justifyContent: "center",
alignItems: "center",
...(isKeyboardOpen && {
display: "none",
}),
},
form: {
flex: 1,
}
})
);
I made this into a npm package if anyone is interested.
https://github.com/TIKramer/react-native-hide-onkeyboard
You can hide the view by using HideOnKeyboard> </HideOnKeyboard
I call an api https://obscure-reaches-65656.herokuapp.com/api/getCloseTime?city=Miaoli&sTime=21&eTime=24 to my react-redux action and use SectionList to show the data.
With official tutorial, i use SectionList it will just show all of the section, i try to find the way when click title that can expand or collapse the section.
I find my sectionComp and renderSectionItem use the same title so i try use this.state{ title: '', expand: false }
When i click 國興戲院 use this.setState({ title: '國興戲院', expand: true }) and use like if(this.state.expand) {} in renderSectionItem
Obviously its not working because i may have a lot of section.
I have no idea what next step should i try.
Any help would be appreciated. Thanks in advance.
Here is my SectionList data:
Here is my class component:
import React, { Component } from 'react';
import { Text, SectionList, TouchableOpacity } from 'react-native';
import { connect } from 'react-redux';
import { View } from 'react-native-animatable';
import { fetchSearchTime } from '../actions';
import { Spinner } from './common';
import GetUserTime from '../function/common/GetUserTime';
class MovieCloseTime extends Component {
constructor(props) {
super(props);
const { selectedCity, firstSliderValue, secondSliderValue }
= this.props.navigation.state.params;
this.state = {
selectedCity,
firstSliderValue,
secondSliderValue,
};
}
componentDidMount() {
const { selectedCity, firstSliderValue, secondSliderValue } = this.state;
this.props.fetchSearchTime({
selectedCity, firstSliderValue, secondSliderValue
});
}
sectionComp = (info) => {
const theaterCn = info.section.title;
console.log('Title info is =>');
console.log(info);
return (
<TouchableOpacity
onPress={() => console.log('Hot to expand and collapse specify section when click here?')}
>
<View style={{ flex: 1, backgroundColor: '#DCDCDC' }}>
<Text style={styles.sectionTitle}>{theaterCn}</Text>
</View>
</TouchableOpacity>
);
}
renderSectionItem = (info) => {
const cnName = info.item.cnName;
console.log('Section info is =>');
console.log(info);
return (
<TouchableOpacity
onPress={() => {
this.props.navigation.navigate('MovieDetail', {
enCity: this.state.selectedCity,
cnName
});
}
}
>
<View style={{ flex: 1, flexDirection: 'column' }}>
<Text style={styles.sectionSubTitle}>{cnName}</Text>
<View style={{ flexDirection: 'row', flexWrap: 'wrap', backgroundColor: '#F8F8FF' }}>
{info.item.releasedTime.map((value, index) => {
const theTime = GetUserTime.getAsiaTime(value, 'YYYY/MM/DD HH:mm:ss');
const hour = theTime.getHours();
const minute = (theTime.getMinutes() < 10 ? '0' : '') + theTime.getMinutes();
return (
<Text style={styles.sectionTimeTitle} key={index}>{`${hour}:${minute}`}</Text>
);
})
}
</View>
</View>
</TouchableOpacity>
);
}
render() {
const movieData = this.props.searchTime;
if (this.props.loading) {
return <Spinner text='Loading...' />;
}
console.log('movieData is =>');
console.log(movieData);
return (
<View style={{ flex: 1 }}>
<SectionList
renderSectionHeader={this.sectionComp}
renderItem={this.renderSectionItem}
sections={movieData}
keyExtractor={(item, index) => index}
ItemSeparatorComponent={() => <View style={styles.separator} />}
/>
</View>
);
}
}
const mapStateToProps = (state) => {
const searchTime = state.searchTime.searchList;
const loading = state.searchTime.loading;
return { searchTime, loading };
};
const styles = {
// some styles
};
export default connect(mapStateToProps, { fetchSearchTime })(MovieCloseTime);
Here is my action fetchSearchTime:
export const fetchSearchTime = ({ selectedCity, firstSliderValue, secondSliderValue }) => {
return (dispatch) => {
dispatch({ type: SEARCH_TIME_REQUEST });
console.log(`https://obscure-reaches-65656.herokuapp.com/api/getCloseTime?city=${selectedCity}&sTime=${firstSliderValue}&eTime=${secondSliderValue}`);
fetch(`https://obscure-reaches-65656.herokuapp.com/api/getCloseTime?city=${selectedCity}&sTime=${firstSliderValue}&eTime=${secondSliderValue}`)
.then(response => response.json())
.then(responseData => {
const movieData = responseData.reduce((r, s) => {
r.push({ title: s.theaterCn, id: s._id, expand: true, data: s.movie });
return r;
}, []);
//dispatch({ type: SEARCH_TIME, payload: responseData });
dispatch({ type: SEARCH_TIME, payload: movieData });
})
.catch((error) => console.log(error));
};
};
about type SEARCH_TIME reducer:
// with others type
import {
SEARCH_TIME_REQUEST,
SEARCH_TIME
} from '../actions/types';
const INITIAL_STATE = {
searchList: [],
loading: true,
selectedCity: '',
firstSliderValue: '',
secondSliderValue: ''
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case SEARCH_TIME_REQUEST:
return {
searchList: [],
loading: true,
};
case SEARCH_TIME:
return {
searchList: action.payload,
loading: false
};
default:
return state;
}
};
I am new to react-native redux , i am updating my old code which i build by using flux pattern in Redux architecture , i am learning the usage of store , thunk , reducers and Actions , Here is some of my classes which i updated :-
HomeScreenClass :-
import React, { Component } from "react";
import {
StyleSheet,
View,
StatusBar,
ActivityIndicator,
Modal,
Platform,
Image,
ScrollView,
TouchableOpacity
} from "react-native";
import { Card } from "native-base";
import NavigationDrawer from "../../component/navigationDrawerComponent/NavigationDrawer";
import CategoryProductList from "../HomeScreen/screens/CategoryProducts";
import CustomText from "../../component/customComponent/CustomText";
import ProductScreen from "./screens/ProductScreen";
import ProductDetailScreen from "./screens/ProductDetailScreen";
import PopUpMenu from "../../component/navigationDrawerComponent/PopUpMenu";
import { Font } from "expo";
import LoginScreen from "../AuthScreen/LoginScreen";
import SignUp from "../AuthScreen/SignUpScreen";
import WebApi from "../../component/webServiceComponent/WebServiceHandler";
import ForgotPassword from "../AuthScreen/ForgotPassword";
import SignUpScreen from '../AuthScreen/SignUpScreen';
import ProfileScreen from "./screens/ProfileScreen";
import ChangePassword from "../AuthScreen/ChangePassword";
import EditProfileScreen from "./screens/EditProfileScreen";
import HtmlView from "./screens/HtmlView";
import OfflineNotice from "../../component/internetCheckComponent/OfflineNotice";
import { createRouter, NavigationProvider } from "#expo/ex-navigation";
import metrics from "../../component/displaySizeComponent/metrics";
import { connect } from 'react-redux';
import { HitAllApis} from '../../actions/ApiCallActions';
var self;
export const Router = createRouter(() => ({
about: () => AboutScreen,
products: () => ProductScreen,
aboutUs: () => AboutUs,
terms: () => Terms,
rateUs: () => RateUs,
productDetails: () => ProductDetailScreen,
ProductListing: () => CategoryProductList,
feedback: () => Feedback,
htmlView: () => HtmlView,
loginScreen: () => LoginScreen,
signUpScreen: () => SignUpScreen,
profileScreen: () => ProfileScreen,
editProfileScreen: () => EditProfileScreen,
forgotPasswordScreen: () => ForgotPassword,
changePassword: () => ChangePassword
}));
class HomeScreen extends Component {
constructor(props) {
super(props);
this.state={
modalVisible: false,
loaded: false
}
self = this;
}
componentWillMount() {
console.disableYellowBox = true;
self._loadFontsAsync();
const {dispatch} = this.props;
dispatch(HitAllApis());
}
componentDidMount() {
console.log("component*****" , this.props);
}
closeModal() {
this.setState({ modalVisible: false });
}
openModal() {
if (this.state.modalVisible) {
this.setState({ modalVisible: false });
} else {
this.setState({ modalVisible: true });
}
}
_loadFontsAsync = async () => {
await Font.loadAsync({
futuraLigtBt: require("../../fonts/futuraLightBt.ttf")
});
this.setState({ loaded: true });
};
render() {
console.log("under Render ", this.props)
if (!this.props.showData || !this.state.loaded) {
return (
<View style={{ flex: 1 }}>
<Image
style={{
height: metrics.DEVICE_HEIGHT + 24,
width: metrics.DEVICE_WIDTH
}}
source={require("../../assets/splash.png")}
/>
<ActivityIndicator
color="white"
style={styles.activityIndicator}
size="small"
animating={this.props.isLoading}
/>
<OfflineNotice />
</View>
);
}
return (
<View style={styles.container}>
<NavigationProvider router={Router}>
<StatusBar barStyle="default" hidden={false} />
<NavigationDrawer
openMenu={() => this.openModal()}
disableBack={true}
magentoData={this.props.magentoData}
bannerData={this.props.bannerData}
categoryList={this.props.categoryList}
/>
</NavigationProvider>
<Modal
transparent={true}
visible={this.state.modalVisible}
animationType={"none"}
onRequestClose={() => this.closeModal()}
>
<View style={styles.modalContainer}>
<View style={styles.modalInnerContainer}>
<TouchableOpacity
style={styles.navBar}
onPress={() => this.closeModal()}
/>
<View style={{ flex: 1, backgroundColor: "white" }}>
<Card>
<ScrollView showsVerticalScrollIndicator={false}>
<View style={styles.scrollView}>
<PopUpMenu
popUpList={this.state.popUpPageData}
closePopUp={() => this.closeModal()}
/>
</View>
</ScrollView>
</Card>
</View>
</View>
<TouchableOpacity
style={{ flex: 0.5, color: "transparent" }}
onPress={() => this.closeModal()}
/>
</View>
</Modal>
<OfflineNotice />
</View>
);
}
}
function mapStateToProps(state) {
//const { magentoData: [],showData,isLoading,popUpPageData: [],categoryList: [],bannerData: [],loaded,modalVisible} = state
return {
state
}
}
export default connect(mapStateToProps)(HomeScreen)
const styles = StyleSheet.create({
modalInnerContainer: {
flex: 0.5,
justifyContent: "center",
backgroundColor: "transparent",
flexDirection: "column"
},
container: { flex: 1, justifyContent: "center", alignItems: "center" },
activityIndicator: { position: "absolute", bottom: 20, alignSelf: "center" },
navBar: {
...Platform.select({
ios: {
height: 63
},
android: {
height: 55
}
}),
color: "transparent"
},
container: {
flex: 1,
backgroundColor: "white",
alignItems: "center",
justifyContent: "center"
},
scrollView: {
flex: 1,
borderRadius: 3,
justifyContent: "flex-start",
backgroundColor: "white",
shadowColor: "black",
shadowOpacity: 0.2,
shadowRadius: 3,
shadowOffset: {
height: 0,
width: 0
}
},
modalContainer: {
flex: 1,
flexDirection: "column",
justifyContent: "center",
backgroundColor: "transparent"
}
});
In the above class i have used Ex-natvigation , i have connected this class with Reducer.In Above when i am trying to update connection line by export default connect(mapStateToProps,{HitAllApis})(HomeScreen) , it shows me syntax error.
Here is what my Action class looks like :-
import * as types from '../types/ActionTypes'
import WebApi from "../component/webServiceComponent/WebServiceHandler";
function getCategorylisting() {
console.log('category');
return WebApi.GetApihit("/restapi/index/CategoryListing", null);
}
function getdashboard() {
console.log('das');
return WebApi.GetApihit("/restapi/index/getdashboard", null);
}
function getBanner() {
console.log('Banner');
return WebApi.GetApihit("/bannersliderapp/banner/banner", null);
}
function getStaticPages() {
return WebApi.GetApihit("/restapi/staticpages/getPages/", null);
}
export function HitAllApis (){
return function (dispatch) {
WebApi.fetchHeader().then(
function () {
Promise.all([
getCategorylisting(),
getdashboard(),
getBanner(),
getStaticPages()
]).then(function (response) {
dispatch({ type: types.Api_Response_case, data: response });
}, function (Error) {
dispatch({ type: types.Api_Request_case, data: response });
});
},
function (error) {
console.log(error);
}
);
}
}
I have requirement that i need to get data from multiple Api's , so i use promise in the Action class and grab data in one single response Object
My Store class :-
import {createStore, applyMiddleware} from 'redux';
import thunkMiddleware from 'redux-thunk';
import rootReducer from '../reducers/index';
const createStoreWithMiddleware = applyMiddleware(thunkMiddleware)(createStore);
export default function configureStore(initialState) {
const store = createStoreWithMiddleware(rootReducer, initialState);
return store;
}
My Reducer class :-
import * as type from '../types/ActionTypes'
const initialState =({
magentoData: [],
showData: false,
isLoading: false,
popUpPageData: [],
categoryList: [],
bannerData: []
})
export default function DashBoardData(state = initialState, action = {}) {
switch (action.type) {
case type.Api_Request_case:
return state.isLoading = true;
case type.Api_Response_case:
state.isLoading = false;
state.showData=true;
state.categoryData = action.data[0];
state.magentoData = action.data[1];
state.bannerData = action.data[2];
state.popUpPageData = action.data[3];
// console.log('categoryData****', state.categoryData);
// console.log('magentoData****', state.magentoData);
// console.log('bannerData****', state.bannerData);
// console.log('popUpPageData****', state.popUpPageData);
return {...state};
default:
return state
}
}
And this is what i am getting inside my console.log("under Render ", this.props) :-
Object {
"dispatch": [Function anonymous],
"state": Object {
"DashBoardData": Object {
"bannerData": Array [],
"categoryList": Array [],
"isLoading": false,
"magentoData": Array [],
"popUpPageData": Array [],
"showData": false,
},
},
}
I might be doing wrong , please let me know is my approach is fine or i need to implement this in some other way , If i am doing anything wrong here Please let me know my mistake so that i can understand it more clearly.
Any Help would be greatly Appreciated!!!
Thanks
React re-renders when it determines that the old state is different from the new state. But you're modifying the old state and then copying it into the new state you return, so it thinks nothing has changed.
Your reducer should only read from the state object, it should not make modifications. For example:
export default function DashBoardData(state = initialState, action = {}) {
switch (action.type) {
case type.Api_Request_case:
return {
...state, // old state is NOT modified
isLoading: true // this is only set for the NEW state
};
case type.Api_Response_case:
return {
...state, // initially use what's in the OLD state,
isLoading: false, // then include the vales you are changing.
showData: true,
categoryData: action.data[0],
magentoData: action.data[0],
bannerData: action.data[0],
popUpPageData: action.data[0],
default:
// this REALLY means nothing has changed,
// React will not re-render
return state;
}
}