Mixed up default and named imports? - javascript

Working on displaying data in my Firebase Cloud Firestore, but I get an error when in my code. Can't understand what the issue is?
I have tried using export default in a new file, instead of using class for my RootStack, but I get an error when I try to do that as well.
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
const RootStack = createStackNavigator(
{
Auth: {
screen: Auth, navigationOptions: { header: null },
},
Login: {
screen: Login, navigationOptions: { header: null },
},
Home: {
screen: Home, navigationOptions: { header: null },
},
}
);
class Home extends React.Component {
constructor(props){
super(props);
this.state = ({
todoTasks: []
})
this.ref = firestore.collection("tips");
}
componentDidMount() {
this.unsubscribe = this.ref.onSnapshot((querySnapshot) => {
const todos = [];
querySnapshot.forEach((doc) => {
todos.push({
tips: doc.data().tips
})
})
this.setState({
todoTask: todos
})
})
}
render() {
return (
<View>
<Flatlist
data={this.state.todoTask}
renderItem={({ item, index }) => {
return(
<Text>{item.tips}</Text>)
}}
>
</Flatlist>
</View>
)
}
}

Related

How to Load AsyncStorage Data on App Load and set to context in Expo?

I created an Expo project and I am setting some data to LocalStorage using AsyncStorage.
I want to reload that data on App start and want to assign that data to context/State.
How I can achieve that any one can help me to solve this problem.
here is my code of app.js
import React from 'react';
import { Asset } from 'expo-asset';
import * as Font from 'expo-font';
import { AppLoading } from 'expo';
....
const client = new ApolloClient({
// link: new HttpLink({
uri:'',
request: (operation) => {
getToken().then(token=>{
console.log('APIToken:', token);
operation.setContext({
headers: {
'api-token': token ? `${token}` : ''
}
})
});
},
//}),
cache: new InMemoryCache(),
});
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fffef9',
},
});
export default class App extends React.Component {
constructor(props) {
super(props);
this.updateContext=(key, value)=>{
this.setState({
[key]: value
});
};
this.updateStack=(stack)=>{
this.setState({
activeStack: stack
});
};
this.loadUsers=(users, _activeUser)=>{
console.log('Users:', users);
this.setState({
users: users,
activeUser: _activeUser
});
};
this.logOutUser=()=>{
this.setState({
activeUser: {},
users:[],
activeStack:'Auth'
});
};
this.state = {
isReady: false,
activeUser:{},
users: [],
activeStack:'Auth',
updateStack: this.updateStack,
updateContext: this.updateContext,
loadUsers: this.loadUsers,
logOutUser: this.logOutUser
};
}
render() {
if (!this.state.isReady) {
return (
<AppLoading
startAsync={this._cacheResourcesAsync}
onFinish={(res) => {this.setState({ isReady: true })}}
onError={console.warn}
/>
); }
return (
<ApolloProvider client={client}>
<SafeAreaProvider>
<SafeAreaView forceInset={{ bottom: 115 }} style={styles.container}>
{Platform.OS === 'ios' && <StatusBar barStyle="default" />}
<AppContext.Provider value={this.state}>
<AppNavigator/>
</AppContext.Provider>
</SafeAreaView>
</SafeAreaProvider>
</ApolloProvider>
);
}
async _cacheResourcesAsync() {
await Promise.all([
Asset.loadAsync([
// require('./assets/images/robot-dev.png'),
]),
Font.loadAsync({
'body': require('./assets/fonts/Archivo-Regular.ttf'),
'body-bold': require('./assets/fonts/Archivo-SemiBold.ttf'),
'headline': require('./assets/fonts/Nunito-Medium.ttf'),
'headline-bold': require('./assets/fonts/Nunito-Bold.ttf'),
'headline-extra-bold': require('./assets/fonts/Nunito-ExtraBold.ttf'),
})
]);
}
}
I have a function to loaduser() in a separate file, where i am loading users from localstorage and returning a promise. You can tell me where i should call loadUser() and handle its promise to loadState.
Thanks
I had the same problem. My solution was create another Component.
My App.js:
export default () => {
const [isReady, setIsReady] = useState(false);
const loadAssetsAsync = async () => {
const imageAssets = cacheImages([
require('./assets/images/bg_screen1.jpg'),
require('./assets/images/bg_screen2.jpg'),
require('./assets/images/bg_screen3.jpg'),
require('./assets/images/bg_screen4.jpg'),
require('./assets/images/user-cool.png'),
require('./assets/images/user-hp.png'),
require('./assets/images/user-student.png'),
require('./assets/images/avatar1.jpg'),
]);
const fontAssets = cacheFonts([
...vectorFonts,
{ georgia: require('./assets/fonts/Georgia.ttf') },
{ regular: require('./assets/fonts/Montserrat-Regular.ttf') },
{ light: require('./assets/fonts/Montserrat-Light.ttf') },
{ bold: require('./assets/fonts/Montserrat-Bold.ttf') },
{ UbuntuLight: require('./assets/fonts/Ubuntu-Light.ttf') },
{ UbuntuBold: require('./assets/fonts/Ubuntu-Bold.ttf') },
{ UbuntuLightItalic: require('./assets/fonts/Ubuntu-Light-Italic.ttf') },
]);
await Promise.all([...imageAssets, ...fontAssets]);
};
if (!isReady) {
return (
<AppLoading
startAsync={loadAssetsAsync}
onFinish={() => setIsReady(true)}
onError={console.warn}
/>
);
}
return <RootNavigator />;
};
My RootNavigator:
export default () => {
const [loaded, setLoaded] = useState(false);
const [init, setInit] = useState(false);
useEffect(() => {
const fetchData = async () => {
const type = await getUserType()
const name = await getName()
const UID = await getUID()
const token = await getToken()
if (!type || !name || !UID || !token) {
inital = 'Login'
} else if (type === 'CLIENT') {
inital = 'Client'
} else if (type === 'EMPLOYEEE') {
inital = 'Employee'
}
setInit(inital)
}
fetchData()
}, [])
function returnRoute() {
AppNavigator = createStackNavigator({
Login: {
screen: LoginScreen,
navigationOptions: {
headerShown: false
}
},
Client: {
screen: DrawerNavigator,
navigationOptions: {
headerShown: false,
},
},
StoreBooking: StoreBookingScreen,
StoreContract: StoreContractScreen,
IndexContracts: IndexContractsScreen,
ShowActivity: ShowActivityScreen,
ShowUniqueBooking: ShowUniqueBookingScreen,
Addresses: ShowAddressesScreen,
},
{
initialRouteName: init,
defaultNavigationOptions: {
headerStyle: {
backgroundColor: cli.Client.b1,
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}
})
RootNavigator = createAppContainer(AppNavigator);
return <RootNavigator />
}
return (
loaded && init ? (
<Awaiter />
)
:
returnRoute()
)
}

How can I update High Order Component

I created array of routing in ReactJS
const routes = [
{ id: 0, path: '/', view: Home, parent: 0 },
{ id: 1, path: '/a', view: Home2, parent: 0 },
{ id: 2, path: '/b', view: Home3, parent: 1 }
]
Created HOC withAuth which should back to parent routing when user isn't logged. When i going to route (as not logged) - its ok and withAuth back me to parent route, but when i am on route and logout page isn't refresh and I am stay on route for logged users.
import React, { Component } from "react";
import AuthHelper from "./AuthHelper";
export default function withAuth(AuthComponent) {
const Auth = new AuthHelper();
class AuthWrapped extends Component {
constructor(props) {
super(props);
this.state = {
confirm: null,
loaded: false
};
}
checkLogged = () => {
if (!Auth.loggedIn()) {
const parent = this.props.parent;
const obj = this.props.routes
.filter(v => v.id === parent);
this.props.history.replace(obj[0].path);
} else {
try {
const confirm = Auth.getConfirm();
this.setState({
confirm: confirm,
loaded: true
});
} catch (err) {
Auth.logout();
this.props.history.replace("/");
}
}
}
componentDidMount() {
this.checkLogged();
}
render() {
if (this.state.loaded) {
if (this.state.confirm) {
return (
<AuthComponent
history={this.props.history}
confirm={this.state.confirm}
/>
);
} else {
return null;
}
} else {
return null;
}
}
};
return AuthWrapped;
}
I believe that you are using the authentication system the wrong way
In React everything should exist in a hierarchical manner.
In your case, you have an Auth state that would change and when the loggedIn state changes, everything should re-render. the correct way to do this is using the Context API to handle the logged in state so when the state changes, the whole screen would re-render
here is the solution to your problem:
AuthContext.js
const AuthContext = React.createContext();
export class AuthProvider extends React.Component {
state = {
isLoggedIn: false,
};
login = (username, password) => {
someLoginRequestToServer(username, password).then(response => {
this.setState({
isLoggedIn: response.isLoggedIn,
});
});
};
logout = () => {
someLogoutRequestToServer().then(() => {
this.setState({ isLoggedIn: false });
});
};
render() {
return (
<AuthContext.Provider
value={{
loggedIn: this.state.isLoggedIn,
login: this.login,
logout: this.logout,
}}>
{this.props.children}
</AuthContext.Provider>
);
}
}
export const AuthConsumer = AuthContext.Consumer;
SomeCustomAuthComponent
class CustomAuthComponent extends React.Component {
render() {
return (
<AuthConsumer>
{({ loggedIn, login, logout }) => (
<div>
<p>You Are {loggedIn ? 'Logged in' : 'Logged out'}</p>
<button onClick={loggedIn ? () => logout() : () => login('abcd', '12345')} />
</div>
)}
</AuthConsumer>
);
}
}
Or you can use the redux for state management and react-redux as it uses the react Context API under the hood.
hope this helps you! :)
the problem lays here
componentDidMount() {
this.checkLogged();
}
you're checking if the user is logged only when the component is mounted (after the instantiation). you should be checking it every time the page updates, you have to identify a way to handle this mechanism for example by using the componentDidUpdate hook.
export default function withAuth(AuthComponent) {
const Auth = new AuthHelper();
class AuthWrapped extends Component {
constructor(props) {
super(props);
this.state = {
confirm: null,
loaded: false
};
}
checkIsNotLogged = () => {
const parent = this.props.parent;
const obj = this.props.routes
.filter(v => v.id === parent);
this.props.history.replace(obj[0].path);
}
checkLogged = () => {
if (!Auth.loggedIn()) {
this.checkIsNotLogged();
} else {
try {
const confirm = Auth.getConfirm();
this.setState({
confirm: confirm,
loaded: true
});
} catch (err) {
Auth.logout();
this.props.history.replace("/");
}
}
}
componentDidMount() {
this.checkLogged();
}
componentDidUpdate() {
// do not call here the checkLogged method otherwise you could trigger an infinite loop
this.checkIsNotLogged();
}
render() {
if (this.state.loaded) {
if (this.state.confirm) {
return (
<AuthComponent
history={this.props.history}
confirm={this.state.confirm}
/>
);
} else {
return null;
}
} else {
return null;
}
}
};
return AuthWrapped;
}

How to Define Child Navigator's Initial Route Name from Parent Navigator?

I managed to pass initial route name from parent navigator to child navigator, but Log Out button in Drawer is not working (do nothing, no errors). Is it because I created multiple AppContainers?
NavApp.js
const routeConfigs = {
NavGuest: { screen: NavGuest },
NavDrawer: { screen: NavDrawer }
}
const AppContainerIn = (props) => {
navConfigs.initialRouteName = props.initialRouteName;
let switchNav = createSwitchNavigator(routeConfigs, navConfigs);
let AppContainerOut = createAppContainer(switchNav);
return <AppContainerOut />
}
export default class NavApp extends Component {
render() {
return (
<AppContainerIn initialRouteName={this.props.initialRouteName} />
)
}
}
NavDrawer.js
const routeConfigs = {
Wizard: { screen: Wizard },
NavHomeSearch: { screen: NavHomeSearch },
}
const navConfigs = {
contentComponent: SideMenu,
drawerWidth: Dimensions.get('window').width - 120,
}
const ContainerDrawerIn = (props) => {
navConfigs.initialRouteName = props.initialRouteName;
let NavDrawer = createDrawerNavigator(routeConfigs, navConfigs);
let ContainerDrawerOut = createAppContainer(NavDrawer);
return <ContainerDrawerOut />
}
export default class ContainerDrawer extends Component {
render() {
return (
<ContainerDrawerIn initialRouteName={this.initialRouteName} />
)
}
}
SideMenu.js
export default class SideMenu extends Component {
constructor(props) {
super(props);
this.navigation = props.navigation;
}
logout = () => {
AsyncStorage.removeItem('isLoggedin');
// Help, not going anywhere. Btw, isLoggedin is successfully removed.
this.props.navigation.navigate('NavGuest');
}
render() {
return (
<View>
<Button title='Log Out' onPress={() => this.logout()} />
</View>
)
}
}
Common mistake: Explicitly rendering more than one navigator.
https://reactnavigation.org/docs/en/common-mistakes.html
export default class App extends React.Component {
render() {
/* In the root component we are rendering the app navigator */
return <AppContainer />;
}
}
const AuthenticationNavigator = createStackNavigator({
SignIn: SignInScreen,
ForgotPassword: ForgotPasswordScreen,
});
class AuthenticationScreen extends React.Component {
static router = AuthenticationNavigator.router;
render() {
return (
<AuthenticationNavigator navigation={this.props.navigation} />
);
}
}
const AppNavigator = createSwitchNavigator({
Auth: AuthenticationScreen, // This screen renders a navigator!
Home: HomeScreen,
});
const AppContainer = createAppContainer(AppNavigator);

onPress not getting called , throwing an error

I have following code where onPress i m expecting to call a function.
class BarButton extends Component {
render() {
const {imageUri,onPress} = this.props;
return (
<TouchableOpacity style={styles.buttonStyle}
onPress={() => onPress()}
>
<Image source={imageUri} style = {styles.buttonStyle}/>
</TouchableOpacity>
);
}
}
BarButton.propTypes = {
onPress: PropTypes.func.isRequired,
imageUri:PropTypes.string.isRequired
};
export default class ShopScreen extends Component {
static navigationOptions = {
title: 'Shop',
headerRight: <BarButton imageUri={require('./images/filter.png')} onPress={ this.onPressButton}/>,
headerTintColor:'black'
};
constructor(props){
super(props);
this.state ={ isLoading: true}
this.onPressButton = this.onPressButton.bind(this);
}
onPressButton()
{
this.props.navigation.navigate('Filter');
}
So I want to call the function onPressButton and navigate to next screen , in this I get error
You can use the navigation object that navigationOptions receive when you use a function instead of an object.
static navigationOptions = ({ navigation }) => {
return {
title: 'Shop',
headerRight: (
<BarButton
imageUri={require('./images/filter.png')}
onPress={() => navigation.navigate('Filter')}
/>
),
headerTintColor:'black'
};
};
Basically as a newbie i failed to understand that navigationOptions is a static var so can't reference anything using "this", following thread proposes many solutions here is the original link and out of all the on worked for me is as follows, posting it here for ease (with due credit to original author https://github.com/jacse)
https://github.com/react-navigation/react-navigation/issues/145
class MyScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerRight: <Button title="Save" onPress={() => params.handleSave()} />
};
};
_saveDetails = () => {
console.log('clicked save');
console.log('clicked save ' + this.state.xxxxxx);
}
componentDidMount() {
this.props.navigation.setParams({ handleSave: this._saveDetails });
}
render() {
return (
<View />
);
}
}

React Native - How to append to parent state array while in child component (StackNavigators)?

My project is looping through a data array in a child component Main, and I'm trying to update the state in parent component, App, on an event (swiping right on a card in Main), so that I could access the data that was 'swiped right' on a sibling Component in Favorites. Hopefully that makes sense?
The project structure is as such:
App
|__ Rootstack
|
|__Favorites
|__Main
In my Main component, I am mapping the collection array and looping thru:
collection = imagedata;
// a local JSON array of data that I am looping thru in Main
class Main extends React.Component {
_toFavs = () => {
this.props.navigation.navigate('Favorites');
};
render() {
const contents = collection.map((item, index) => {
return (
<Card key={index}>
......
</Card>
)
});
return (
<View>
<CardStack
onSwiped={() => {console.log('onSwiped')}
onSwipedRight={() => console.log('onSwipedLeft')}>
//
//HERE IS THE PART - HOW TO UPDATE THE 'favoritesList' array in the parent 'App's state?
//
{contents}
</CardStack>
</View>
);
}
}
const RootStack = StackNavigator(
{
Main: {
screen: Main},
Favorites: {
screen: Favorites}
},
{
initialRouteName: 'Main'
}
);
class Favorites extends React.Component {
// The plan is to eventually access the favoritesList array in App's state here and display cards that were swiped right in the Main component.
_onPress = () => {
this.props.navigation.navigate('Main');
};
render() {
return (
<View><Text>Hello!</Text></View>
);
}
}
export default class App extends Component<{}> {
constructor(props) {
super(props);
this.state = {
favoritesList: []
};
}
render() {
return <RootStack />;
}
}
I've come across some other answers of updating state such as
this.setState({ favoritesList: [...this.state.favoritesList, 'new value'] }), but how can I do this to the .state of App while i'm inside a child component Main?
Thanks in advance!
collection = imagedata;
// a local JSON array of data that I am looping thru in Main
class Main extends React.Component {
_toFavs = () => {
this.props.navigation.navigate('Favorites');
};
render() {
const contents = collection.map((item, index) => {
return (
<Card key={index}>
......
</Card>
)
});
return (
<View>
<CardStack
onSwiped={() => {console.log('onSwiped')}
onSwipedRight={() => {console.log('onSwipedLeft') ;
this.props.screenProps()}}>
//
{contents}
</CardStack>
</View>
);
}
}
const RootStack = StackNavigator(
{
Main: {
screen: Main},
Favorites: {
screen: Favorites}
},
{
initialRouteName: 'Main'
}
);
class Favorites extends React.Component {
// The plan is to eventually access the favoritesList array in App's state here and display cards that were swiped right in the Main component.
_onPress = () => {
this.props.navigation.navigate('Main');
};
render() {
return (
<View><Text>Hello!</Text></View>
);
}
}
export default class App extends Component<{}> {
constructor(props) {
super(props);
this.state = {
favoritesList: []
};
}
updateArr=()=>{consol.log("fire") }
render() {
return <RootStack screenProps={this.updateArr} />;
}
}
i hope it solve your problem
update props-name

Categories

Resources