I am trying to connect my existing react-native project to GrapghQl using relay. __generated__ folder not creating AppQuery.graphql.js
Reference link.
error-
package.json
{
"name": "farmcom",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"relay": "relay-compiler --src ./src --schema ./schema.graphql",
"relayw": "relay-compiler --src ./src --schema ./schema.graphql --watch",
"test": "jest"
},
"dependencies": {
"graphql": "^14.0.2",
"prop-types": "^15.6.2",
"react": "16.5.0",
"react-native": "^0.57.2",
"react-native-collapsible": "^1.2.0",
"react-native-splash-screen": "^3.0.6",
"react-native-vector-icons": "^6.0.2",
"react-navigation": "^2.17.0",
"react-relay": "^1.7.0",
"relay": "^0.8.0-1"
},
"devDependencies": {
"babel-jest": "23.6.0",
"babel-plugin-relay": "^1.7.0",
"jest": "23.6.0",
"metro-react-native-babel-preset": "0.48.0",
"react-test-renderer": "16.5.0",
"relay-compiler": "^1.7.0",
"schedule": "^0.4.0"
},
"jest": {
"preset": "react-native"
}
}
.babelrc
{
"presets": ["module:metro-react-native-babel-preset"],
"plugins": ["relay"]
}
relay-environment.js
const { Environment, Network, RecordSource, Store } = require("relay-runtime");
const source = new RecordSource();
const store = new Store(source);
var myHeaders = new Headers();
// myHeaders.append('Access-Control-Allow-Headers', 'Content-Type');
// myHeaders.append("Content-Type", "multipart/form-data");
myHeaders.append("Content-Type", "application/json");
//'https://us-west-2.api.scaphold.io/graphql/narrow-pigs'
//'https://api.graph.cool/relay/v1/cj9z8yz7ig1zb0121dl0uwk2n
// Define a function that fetches the results of an operation (query/mutation/etc)
// and returns its results as a Promise:
function fetchQuery(operation, variables, cacheConfig, uploadables) {
return fetch("https://api.graph.cool/relay/v1/cjd4f6t7c35vn0159xw0lfij1", {
method: "POST",
headers: myHeaders,
mode: "cors",
body: JSON.stringify({
query: operation.text, // GraphQL text from input
variables
})
}).then(response => {
return response.json();
});
}
// Create a network layer from the fetch function
const network = Network.create(fetchQuery);
const environment = new Environment({
network,
store
});
export default environment;
App.js
import React, { Component } from "react";
import { StyleSheet, Text } from "react-native";
import SplashScreen from "react-native-splash-screen";
import { graphql, QueryRenderer } from "react-relay";
import ListAccount from "./src/listAccount";
import environment from "./src/relay.environment";
const AppQuery = graphql`
query AppQuery($count: Int!, $after: String) {
viewer {
...listAccount_viewer
}
}
`;
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
authentic: false
};
}
isAuthentic = authentic => {
this.setState({ authentic });
};
componentDidMount() {
SplashScreen.hide();
}
renderCard(item) {
return <Text>{item.text}</Text>;
}
render() {
return (
<QueryRenderer
environment={environment}
query={AppQuery}
variables={{
count: 1
}}
render={({ error, props }) => {
if (error) {
return <Text>{error.message}</Text>;
} else if (props) {
return (
<View>
<ListAccount viewer={props.viewer} />
</View>
);
}
return <Text>App Loading</Text>;
}}
/>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center"
}
});
listAccount.js
import React, { Component } from "react";
import {
Text,
View,
Button,
Checkbox,
TextInput,
TouchableOpacity
} from "react-native";
import { graphql, createPaginationContainer } from "react-relay";
import Account from "./account";
class ListAccount extends Component {
_loadMore() {
if (!this.props.relay.hasMore()) {
console.log(`Nothing more to load`);
return;
} else if (this.props.relay.isLoading()) {
console.log(`Request is already pending`);
return;
}
this.props.relay.loadMore(1);
}
render() {
return (
<View>
<Text>
{this.props.viewer.allAccounts.edges.map(({ node }, i) => (
<Account key={i} account={node} />
))}
</Text>
<Button onPress={() => this._loadMore()} title="more..." />
</View>
);
}
}
export default createPaginationContainer(
ListAccount,
{
viewer: graphql`
fragment listAccount_viewer on Viewer {
allAccounts(first: $count, after: $after, orderBy: createdAt_DESC)
#connection(key: "ListAccount_allAccounts") {
edges {
node {
...account_account
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
`
},
{
direction: "forward",
query: graphql`
query listAccountForwardQuery($count: Int!, $after: String) {
viewer {
...listAccount_viewer
}
}
`,
getConnectionFromProps(props) {
return props.viewer && props.viewer.allAccounts;
},
getFragmentVariables(previousVariables, totalCount) {
return {
...previousVariables,
count: totalCount
};
},
getVariables(props, paginationInfo, fragmentVariables) {
return {
count: paginationInfo.count,
after: paginationInfo.cursor
};
}
}
);
account.js
import React, { Component } from "react";
import { Text } from "react-native";
import { graphql, createFragmentContainer } from "react-relay";
class Account extends Component {
render() {
return <Text>{this.props.account.acno}</Text>;
}
}
export default createFragmentContainer(
Account,
graphql`
fragment account_account on Account {
acno
}
`
);
Related
In React Navigation 6, my research shows that to navigate without a prop I should make a reference and use createNavigationContainerRef. I'm able to pass down the screen name to my dispatch but for some reason when I evaluate the condition with isReady I'm always told it isn't. The code:
App.js:
import React from 'react'
import { NavigationContainer } from '#react-navigation/native'
import 'react-native-gesture-handler'
// Provider
import { Provider as AuthProvider } from './src/context/AuthContext'
// Navigation
import { navigationRef } from './src/navigation/NavRef'
// Screens
import ResolveAuthScreen from './src/screens/ResolveAuthScreen'
const App = () => {
return (
<AuthProvider>
<NavigationContainer ref={navigationRef}>
<ResolveAuthScreen />
</NavigationContainer>
</AuthProvider>
)
}
export default App
ResolveAuthScreen.js:
import React, { useEffect, useContext } from 'react'
// Context
import { Context as AuthContext } from '../context/AuthContext'
const ResolveAuthScreen = () => {
const { tryLocalSignIn } = useContext(AuthContext)
useEffect(() => {
tryLocalSignIn()
}, [])
return null
}
export default ResolveAuthScreen
AuthContext.js (stripped down):
import AsyncStorage from '#react-native-async-storage/async-storage'
// Context
import createContext from './createContext'
// Nav
import * as NavRef from '../navigation/NavRef'
const authReducer = (state, action) => {
switch (action.type) {
case 'signin':
return { errorMessage: '', token: action.payload }
case 'clear_error':
return { ...state, errorMessage: '' }
default:
return state
}
}
const tryLocalSignIn = dispatch => async () => {
const token = await AsyncStorage.getItem('token')
console.log({ token }) // renders token
if (token) {
dispatch({ type: 'signin', payload: token })
NavRef.navigate('TrackListScreen')
} else {
NavRef.navigate('SignUp')
}
}
export const { Provider, Context } = createContext(
authReducer,
{ tryLocalSignIn },
{ token: null, errorMessage: '' },
)
NavRef.js:
import { createNavigationContainerRef } from '#react-navigation/native'
export const navigationRef = createNavigationContainerRef()
export function navigate(name, params) {
console.log({ name, params })
if (navigationRef.isReady()) {
console.log('ready')
console.log({ name, params })
navigationRef.navigate('TrackDetailScreen', { name, params })
} else {
console.log('not ready')
}
}
When I log the token from dispatch I get back the token. When I log the screen I get back TrackListScreen from navigate but whenever it's fired it always returns the console log of not ready.
Docs:
Navigating without the navigation prop
Navigating to a screen in a nested navigator
"dependencies": {
"#react-native-async-storage/async-storage": "~1.15.0",
"#react-navigation/bottom-tabs": "^6.0.9",
"#react-navigation/native": "^6.0.6",
"#react-navigation/native-stack": "^6.2.5",
"axios": "^0.24.0",
"expo": "~43.0.0",
"expo-status-bar": "~1.1.0",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.2",
"react-native-elements": "^3.4.2",
"react-native-gesture-handler": "~1.10.2",
"react-native-reanimated": "~2.2.0",
"react-native-safe-area-context": "3.3.2",
"react-native-screens": "~3.8.0",
"react-native-web": "0.17.1"
},
Why is my navigate not working after my dispatch or why does the isReady false?
I'm having the same issue. When trying to access the exported navigationRef.isReady() from a redux-saga file, it always returns false. I'm not sure this is a safe approach, nor have I properly tested this, but the following workaround seems to work for me:
App.js
import {setNavigationRef, navigationIsReady} from './NavigationService';
const navigationRef = useNavigationContainerRef();
return (
<NavigationContainer
ref={navigationRef}
onReady={() => {
setNavigationRef(navigationRef);
}}>
...
</NavigationContainer>
);
NavigationService.js
export let navigationRefCopy = undefined;
export function setNavigationRef(navigationRef) {
navigationRefCopy = navigationRef;
}
export function navigationIsReady() {
return navigationRefCopy?.isReady(); // returns true when called in a redux saga file.
}
i'm really new to react native and i encountered this error:
Components\MovieFocusCard.tsx: Assert fail
Failed building JavaScript bundle.
when trying to run the app.
i already tried removing & reinstalling node_modules but it didn't help.
i have no clue why this error is showing up and what the error message itself means. So any help is welcome!
Thanks in advance!
this is the error that shows up on the phone:
package.json:
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"#expo/vector-icons": "^10.0.0",
"babel-preset-react-native": "^4.0.0",
"expo": "^35.0.0",
"react": "16.8.3",
"react-dom": "16.8.3",
"react-native": "https://github.com/expo/react-native/archive/sdk-35.0.0.tar.gz",
"react-native-gesture-handler": "~1.3.0",
"react-native-reanimated": "~1.2.0",
"react-native-screens": "~1.0.0-alpha.23",
"react-native-paper": "^3.3.0",
"react-native-web": "^0.11.7",
"react-navigation": "^4.0.10",
"react-navigation-material-bottom-tabs": "^2.1.5",
"react-navigation-stack": "^1.10.3"
},
"devDependencies": {
"#types/react": "^16.9.14",
"#types/react-native": "^0.57.65",
"#types/react-navigation": "^3.4.0",
"babel-preset-expo": "^7.1.0",
"typescript": "^3.6.3"
},
"private": true
}
Below the code from the MovieFocusCard component:
import MovieDetails from "../Types/MovieDetails";
import { NavigationInjectedProps, withNavigation } from "react-navigation";
import React, { Component } from "react";
import { View, Text, Button, Image } from "react-native";
type MovieFocusCardProps = {};
type MovieFocusCardState = {
movieDetails: MovieDetails;
loaded: boolean;
};
class MovieFocusCard extends Component<
MovieFocusCardProps & NavigationInjectedProps,
MovieFocusCardState
> {
constructor(props: MovieFocusCardProps & NavigationInjectedProps) {
super(props);
this.state = {
movieDetails: null,
loaded: false
};
}
componentDidMount() {
this.GetMovieDetails(this.props.navigation.getParam("movieId", 0));
}
GetMovieDetails(id: number) {
let url: string = "https://api.themoviedb.org/3/movie/";
let apiKey: string = "?api_key=396734bc8915c8d1569cb4ff49b59c56";
fetch(url + id + apiKey)
.then(result => result.json())
.then(data =>
this.setState({
movieDetails: data,
loaded: true
})
)
.catch(console.log);
}
render() {
let posterUrl: string =
"https://image.tmdb.org/t/p/w200" + this.state.movieDetails.poster_path;
let rdate = new Date(
this.state.movieDetails.release_date
).toLocaleDateString();
let element;
this.state.loaded
? (element = (
<View>
<Text>{this.state.movieDetails.title}</Text>
<Image source={{ uri: posterUrl }} />
<Text>Release date: {rdate}</Text>
<Text>Summary: {this.state.movieDetails.overview}</Text>
<Text>Duration: {this.state.movieDetails.runtime} min</Text>
<Button
title="back"
onPress={() => {
this.props.navigation.goBack();
}}
>
Back
</Button>
</View>
))
: (element = <Text>Loading</Text>);
return { element };
}
}
export default withNavigation(MovieFocusCard);
//export default MovieFocusCard;
app.tsx code:
import React from "react";
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs";
import { Ionicons } from "#expo/vector-icons";
import MovieFocusCard from "./Components/MovieFocusCard";
import MovieHome from "./Components/MovieHome";
import HomeScreen from "./Components/HomeScreen";
const MovieHomeStack = createStackNavigator({
Movies: { screen: MovieHome },
MovieFocusCard: { screen: MovieFocusCard, params: { movieId: Number } }
});
const SerieHomeStack = createStackNavigator({});
const HomeStack = createStackNavigator({});
const MenuBarBottom = createAppContainer(
createMaterialBottomTabNavigator(
{
Movies: {
screen: MovieHomeStack,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Ionicons name="md-videocam" size={26} color={tintColor} />
)
}
},
Series: {
screen: SerieHomeStack,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Ionicons name="md-tv" size={26} color={tintColor} />
)
}
},
Home: {
screen: HomeStack,
navigationOptions: {
tabBarIcon: ({ tintColor }) => (
<Ionicons name="md-heart" size={26} color={tintColor} />
)
}
}
},
{
initialRouteName: "Home",
activeColor: "#000000",
inactiveColor: "#9e9e9e",
barStyle: { backgroundColor: "#ffffff" },
shifting: false //only shows label when clicked
}
)
);
export default MenuBarBottom;
It's been 5 hours that I'm on the problem but decidedly it does not want to work...
I would like to dispatch the event when onScroll is detected on my home component and receive the status "true" or "false" in my TopNavigation component
For now my reducer works well (with a console.log(nextState) before the render) but I have the impression that the connection does not work with connect(mapStatetoProps)(TopNavigation) because my component does not re-render
Thank you for your answers
//TopNavigation
import React from 'react'
import { connect } from 'react-redux'
class TopNavigation extends React.Component {
constructor(props) {
super(props)
}
componentDidMount() {
console.log(this.props.scrollData)
}
}
// Render things...
const mapStatetoProps = (state) => {
return {
scrollData: state.scrollData
}
}
export default connect(mapStatetoProps)(TopNavigation)
// Home
import React from 'react'
import { StyleSheet, View, FlatList } from 'react-native'
import gStyles from '../../../Styles/global'
import { connect } from 'react-redux'
// Partials
import ItemBox from '../../Partials/ItemBox'
import TopNavigation from '../../Partials/TopNavigation'
// Data
import recetteData from '../../../api/recetteData'
class Home extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<View style={styles.mainContainer}>
<FlatList
data={recetteData}
keyExtractor={(item) => item.id.toString()}
onPress={() => this._toggleSet()}
renderItem={({ item }) => <ItemBox item={item} />}
onScroll={(event) => this.props.dispatch({ type: "POSITION", value: event.nativeEvent.contentOffset.y })}
style={styles.flatListContainer} />
<TopNavigation />
</View>
)
}
}
export default connect(mapStateToProps)(Home)
//ScrollData Reducer
const initialState = {
scrollData: {
scrolled: false
}
}
function scrollData(state = initialState, action) {
let nextState
switch (action.type) {
case 'POSITION':
if (action.value > 0) {
nextState = {
...state,
scrollData: {
...state.scrollData,
scrolled: true,
},
}
}
else {
nextState = {
...state,
scrollData: {
...state.scrollData,
scrolled: false
},
}
}
return nextState.scrollData.scrolled
default:
return state
}
}
export default scrollData
//ConfigureStore
import { createStore } from 'redux';
import buttonPreference from './Reducers/buttonPreference'
import scrollData from './Reducers/scrollData'
export default createStore(/*buttonPreference,*/scrollData)
On console (console.log of componentDidMount of TopNavigation):
Object {
"scrolled": false,
}
But no change when i'm scrolling
Here is my package.json
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"eject": "expo eject"
},
"dependencies": {
"expo": "^32.0.6",
"react": "^16.8.3",
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.1.tar.gz",
"react-native-elevated-view": "0.0.6",
"react-native-gesture-handler": "^1.1.0",
"react-native-paper": "^2.12.0",
"react-native-responsive-dimensions": "^2.0.1",
"react-navigation": "^2.0.1",
"react-navigation-material-bottom-tabs": "^0.4.0",
"react-redux": "^6.0.1",
"redux": "^4.0.1"
},
"devDependencies": {
"babel-preset-expo": "^5.0.0",
"react-test-renderer": "^16.6.0-alpha.8af6728",
"schedule": "^0.4.0"
},
"private": true
}
Update
Putting on TopNavigation:
//TopNavigation
constructor(props) {
super(props)
this.state = {
scrolledState: false
}
}
componentDidUpdate(prevProps) { // Instead of componentDidMount
if (this.props.scrollData.scrolled !== prevProps.scrollData.scrolled) {
console.log(this.props.scrollData);
this.setState({ scrolledState: this.props.scrollData });
}
}
But it still doesn't work, no event or state change...
Update 2
The store seems to be work oroperly, the problem more precisely is that it does not update in real time the component.
If I populate the store, I quite and return to the page using navigation, the data is well changed.
The real question is, why the component does not update in real time with the new store data passed by the reducer...
Update 3
Expo in production mode solved problem...
You have done everything right for the most part. The problem is with your TopNavigation file. Two important things to keep in mind here:
componentDidMount() is called only once, when your component is rendered for the first time. So even if your connect works correctly, you will not get more than one call to this function. To check if your props are updated correctly, you can have a console.log() inside componentDidUpdate() as follows:
componentDidUpdate(prevProps) {
if (this.props.scrollData.scrolled !== prevProps.scrollData.scrolled) {
console.log(this.props.scrollData);
}
}
Also keep in mind that this will not cause a re-render of your component. A component re-renders only when the state of the component changes. You can use this change in your props to trigger a state change, which will call the render function again, to trigger a re-render of your component, as follows:
state = {scrolledState: false};
...
...
componentDidUpdate(prevProps) {
if (this.props.scrollData.scrolled !== prevProps.scrollData.scrolled) {
// console.log(this.props.scrollData);
this.setState({scrolledState: this.props.scrollData});
}
}
Hope this helps!
That sounds like a bug with environnement. I launched Expo in production mode and it solved problem.
On folder .expo
//setting.json
{
"hostType": "lan",
"lanType": "ip",
"dev": false, // false for production env
"minify": false,
"urlRandomness": "53-g5j"
}
I hope it can help but it would be desirable to be able to continue working on dev mode...
I report a bug on expo github
The previous answer was right. But to make the code works try the below approach.
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
scrolling: false;
}
}
makeScroll = (event) => {
this.props.dispatch({ type: "POSITION", value: event.nativeEvent.contentOffset.y
});
setTimeout(() => this.setState({scrolling: true}), 150);
}
render() {
return (
<View style={styles.mainContainer}>
<FlatList
data={recetteData}
keyExtractor={(item) => item.id.toString()}
onPress={() => this._toggleSet()}
renderItem={({ item }) => <ItemBox item={item} />}
onScroll={(event) => this.makeScroll(event)}
style={styles.flatListContainer} />
<TopNavigation />
</View>
)
}
}
export default connect(mapStateToProps)(Home)
Instead of directly dispatch at onScroll event. Pass it into a function and do change the local state inside that after dispatch.
I am learning React-native and trying to implement redux.
I have used React-redux & React-thunk perform a Async task from the Action. During the implementation, getting an error e.i. "middleware in not a function" when I run. If I comment out middleware and relevant code then everything works fine.
Here is my code below.
index.js
import React, {Component} from 'react';
import ResetUserContainer from "./src/Components/resetUserContainer"
import {Provider} from 'react-redux'
import {createStore,applyMiddleware} from 'redux'
import {thunk} from 'redux-thunk'
import userResetReducer from "./src/Reducers/ResetReducer"
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(userResetReducer);
export default class App extends Component {
render() {
return (
<Provider store = {store}>
<ResetUserContainer/>
</Provider>
);
}
}
ResetUserContainer.js class.
import React, { Component } from "react";
import { StyleSheet, View, ActivityIndicator } from "react-native";
import { connect } from "react-redux"
import userAction from "./Actions/UserAction"
import PropTypes from "prop-types";
class ResetUserContainer extends Components {
constructor(props) {
super(props);
}
componentDidMount() {
this.props.requestToken();
}
render() {
return (
<View style={styles.container}>
<View style={styles.subContainer}>
onPress={this._onPressButton}
containerStyle={{ marginTop: 20 }}
/>
</View>
</View>
<ActivityIndicator
size="large"
color="red"
style={this.props.isFetching ? styles.centering : styles.hideLoader} />
</View>
);
}
_onPressButton = () => {
// this.props.requestToken();
}
}
ResetUserContainer.propTypes = {
requestToken: PropTypes.func.isRequired,
objectMember: PropTypes.object.isRequired
}
const mapStateToProps = state => {
return {
//Here using objectMember, we can access any member of action class
objectMember: state,
//we can use also like this
isFetching: state.isFetching,
errorMsg: state.errorMsg,
displayMsg: state.displayMsg,
token: state.token
}
}
export default connect(mapStateToProps, { userAction })(ResetUserContainer);
types.js
export const TOKEN_REQUEST_PROCESSED = 'TOKEN_REQUEST_PROCESSED';
export const TOKEN_REQUEST_TOKEN_SUCCEEDED= 'TOKEN_REQUEST_TOKEN_SUCCEEDED';
export const TOKEN_REQUEST_FAILED = 'TOKEN_REQUEST_FAILED';
UserAction.js
import AuthInterface from '../../Interfaces/authInterface';
import UserResetModel from '../../Models/userResetModel';
import SpecialUserModel from '../../Models/specialUserModel';
import { TOKEN_REQUEST_PROCESSED, TOKEN_REQUEST_TOKEN_SUCCEEDED, TOKEN_REQUEST_FAILED } from './types';
export const tokenRequestProcess = () => ({ type: TOKEN_REQUEST_PROCESSED });
export const tokenRequestSuccess = (token) => ({ type: TOKEN_REQUEST_TOKEN_SUCCEEDED, payload: token });
export const tokenRequestFailed = (error) => ({ type: TOKEN_REQUEST_FAILED, payload: error });
export const requestToken = () => {
return async dispatch => {
dispatch(tokenRequestProcess);
let specialuser = new SpecialUserModel("", "");
specialuser.Username = "xyz.com";
specialuser.Password = "xyz.password";
AuthInterface.authenticateSpecialUser(specialuser).then((response) => {
let result = new httpResponseModel();
result = response;
if (result.ErrorCode == "OK") {
dispatch(tokenRequestSuccess(result.token_number))
} else {
//Handel all possible failure by error msg
dispatch(tokenRequestFailed(result.error_msg));
}
}, (err) => {
dispatch(tokenRequestFailed(JSON.stringify(err)));
});
}
};
ResetReducer.js
import {
TOKEN_REQUEST_PROCESSED, TOKEN_REQUEST_TOKEN_SUCCEEDED, TOKEN_REQUEST_FAILED
} from './types';
const initialState = {
isFetching: false,
errorMsg: '',
displayMsg: '',
token: ''
};
const resetReducer = (state = initialState, action) => {
switch (action.type) {
case TOKEN_REQUEST_PROCESSED:
return { ...state, isFetching: true };
case TOKEN_REQUEST_TOKEN_SUCCEEDED:
return { ...state, isFetching: false, displayMsg: action.payload }
case TOKEN_REQUEST_FAILED:
return { ...state, isFetching: false, errorMsg: action.payload }
default:
return state;
}
}
export default resetReducer;
package.json
"dependencies": {
"react": "16.5.0",
"react-native": "^0.57.2",
"react-redux": "^5.0.7",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0"
},
"devDependencies": {
"babel-jest": "23.6.0",
"jest": "23.6.0",
"metro-react-native-babel-preset": "0.48.0",
"react-test-renderer": "16.5.0"
},
Please let me know if I am doing something wrong or missing something.
I have googled but couldn't solve, like here in,
Redux thunk in react native
Thanks in advance.
import {thunk} from 'redux-thunk'
Please check this line. You should change that into below.
import thunk from 'redux-thunk'
I got this issue today morning when I was trying to implement a Fluid Navigation between scenes using react-native-fluid-transitions. After I replace createStackNavigator for createFluidNavigator or FluidNavigator I got the screen issue below:
Invariant Violation: withNavigation can only be used on a view hierarchy of a navigator. The wrapped component is unable to get access to navigation from props or context.
Here are my files
index.js
import React from 'react';
import { Platform } from 'react-native';
import {
SafeAreaView,
createStackNavigator,
} from 'react-navigation';
import screens from '../screens';
import AppDrawer, {
contentOptions as appDrawerContentOptions,
} from '../components/AppDrawer';
import { createFluidNavigator, FluidNavigator } from 'react-navigation-fluid-transitions';
// We already have a status bar from expo
if (Platform.OS === 'android') {
SafeAreaView.setStatusBarHeight(0);
}
const defaultStack = createFluidNavigator (
{
Home: {
screen: screens.CpfCheckScreen
},
Login: {
screen: screens.LoginScreen
},
SelectAssociate: {
screen: screens.SelectAssociateScreen
},
EmailRegister: {
screen: screens.EmailRegisterScreen
},
AssociateSelected: {
screen: screens.AssociatedSelectedScreen
},
Welcome: {
screen: screens.WelcomeScreen
},
Survey: {
screen: screens.SurveyScreen
},
WaitingIndication: {
screen: screens.WaitingIndicationScreen
},
BindingSuccess: {
screen: screens.BindingSuccessScreen
},
AuthenticationSteps: {
screen: screens.AuthenticationStepsScreen
},
ProcessingData: {
screen: screens.ProcessingDataScreen
},
SignaturePicture: {
screen: screens.SignaturePictureScreen
},
// CpfPicture: {
// screen: screens.CpfPictureScreen
// },
ConfirmData: {
screen: screens.ConfirmDataScreen
},
DataValidation: {
screen: screens.DataValidationScreen
},
MembershipTerms: {
screen: screens.MembershipTermsScreen
},
SuccessfullRegistration: {
screen: screens.SuccessfullRegistrationScreen
},
ApprovedRegistration: {
screen: screens.ApprovedRegistrationScreen
},
FailedRegistration: {
screen: screens.FailedRegistrationScreen
},
SecurityQuestion:
{
screen: screens.SecurityQuestionScreen
},
AssociatedLoginScreen: {
screen: screens.AssociatedLoginScreen
},
NewAssociateQuizScreen: {
screen: screens.NewAssociateQuizScreen
},
NewAssociateSuccessScreen: {
screen: screens.NewAssociateSuccessScreen
}
},
{
initialRouteName: 'AssociatedLoginScreen',
headerMode: 'none',
}
)
export default defaultStack;
screens.js
import InitializeScreen from './InitializeScreen';
import LoginScreen from './LoginScreen';
import EmailRegisterScreen from './EmailRegisterScreen';
import CpfCheckScreen from './CpfCheckScreen'
import SelectAssociateScreen from './SelectAssociateScreen'
import AssociatedSelectedScreen from './AssociatedSelectedScreen'
import WelcomeScreen from './WelcomeScreen'
import SurveyScreen from './SurveyScreen'
import WaitingIndicationScreen from './WaitingIndicationScreen'
import BindingSuccessScreen from './BindingSuccessScreen'
import AuthenticationStepsScreen from './AuthenticationStepsScreen'
import SignaturePictureScreen from './SignaturePictureScreen'
import ConfirmDataScreen from './ConfirmDataScreen'
// import RgPictureScreen from './RgPictureScreen'
// import CpfPictureScreen from './CpfPictureScreen'
import ProcessingDataScreen from './ProcessingDataScreen'
import DataValidationScreen from './DataValidationScreen'
import MembershipTermsScreen from './MembershipTermsScreen'
import SuccessfullRegistrationScreen from './SuccessfullRegistrationScreen'
import ApprovedRegistrationScreen from './ApprovedRegistrationScreen'
import FailedRegistrationScreen from './FailedRegistrationScreen'
import SecurityQuestionScreen from './SecurityQuestionScreen'
import AssociatedLoginScreen from './AssociatedLoginScreen'
import NewAssociateQuizScreen from './NewAssociateQuizScreen'
import NewAssociateSuccessScreen from './NewAssociateSuccessScreen'
/*
import ModalScreen from './ModalScreen';
import DetailsRegisterScreen from './DetailsRegisterScreen';
import DashboardScreen from './DashboardScreen';
import TaskDetailsScreen from './TaskDetailsScreen';
import TasksScreen from './TasksScreen';
import EventScreen from './EventScreen';
import TaskStepsScreen from './TaskStepsScreen';
import QRScanScreen from './QRScanScreen';
import TaskSuccessScreen from './TaskSuccessScreen';
import LogoutScreen from './LogoutScreen';
import ProductScreen from './ProductScreen';
import ProductQRScanScreen from './ProductQRScanScreen';
import ProductSuccessScreen from './ProductSuccessScreen';
import ContinueAsScreen from './ContinueAsScreen';
import UserProfileScreen from './UserProfileScreen';
import SocialPageLikeTaskScreen from './SocialPageLikeTaskScreen';
*/
export default {
InitializeScreen,
LoginScreen,
EmailRegisterScreen,
CpfCheckScreen,
SelectAssociateScreen,
AssociatedSelectedScreen,
WelcomeScreen,
SurveyScreen,
WaitingIndicationScreen,
BindingSuccessScreen,
AuthenticationStepsScreen,
SignaturePictureScreen,
// RgPictureScreen,
// CpfPictureScreen,
ConfirmDataScreen,
ProcessingDataScreen,
DataValidationScreen,
MembershipTermsScreen,
SuccessfullRegistrationScreen,
ApprovedRegistrationScreen,
FailedRegistrationScreen,
SecurityQuestionScreen,
AssociatedLoginScreen,
NewAssociateQuizScreen,
NewAssociateSuccessScreen
/*
ModalScreen,
DetailsRegisterScreen,
DashboardScreen,
TaskDetailsScreen,
TasksScreen,
EventScreen,
TaskStepsScreen,
QRScanScreen,
TaskSuccessScreen,
LogoutScreen,
ProductScreen,
ProductQRScanScreen,
ProductSuccessScreen,
ContinueAsScreen,
UserProfileScreen,
SocialPageLikeTaskScreen,*/
};
NewAssociateQuizForm
import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Text } from 'native-base';
import { withFormik } from 'formik';
import { withNavigation } from 'react-navigation';
import yup from 'yup';
import { withApollo } from 'react-apollo';
import Auth from '../lib/auth';
import Button from './Button';
import colors from '../config/colors';
import { moderateScale } from '../config/scaling';
import { Transition } from 'react-navigation-fluid-transitions'
import Carousel, { Pagination } from 'react-native-snap-carousel';
import FormField from './FormField';
import ItemInput from './ItemInput';
import AlertContainer from './AlertContainer';
const enhancer = withFormik({
validationSchema: yup.object().shape({
name: yup
.string()
.required('Este campo é obrigatório'),
}),
mapPropsToValues: props => ({
associate: '',
}),
handleSubmit: (values, { props: { client, navigation }, setSubmitting }) => {
const { associate } = values;
console.log('handling submit')
if (!associate ) {
AlertContainer.show({
message: 'Sócio inexistente',
buttonText: 'Tentar novamente',
});
setSubmitting(false);
return;
}
Auth.loginRequest(associate)
.then(res => {
if (!res || !res.data || !res.data.token) {
// We can't tell much to the user
console.log('not working')
AlertContainer.show({
message: 'Erro interno',
buttonText: 'Tentar novamente',
});
return;
}
const { token } = res.data;
console.log('working')
Auth.login(token, client).then(() => navigation.navigate('App'));
})
.catch(error => {
console.log('error on login request', error);
const { response } = error;
if (response) {
// HTTP Request response
const { status } = response;
let message = 'Erro interno';
if (status === 400) {
message = 'Dados inválidos';
}
if (status === 401) {
message = 'Sócio inválido';
}
AlertContainer.show({
message,
buttonText: 'Tentar novamente',
});
} else {
// Raw error message
const errorString = error.toString();
if (errorString && errorString.indexOf('Network Error') >= 0) {
AlertContainer.show({
message: 'Erro de conexão',
buttonText: 'Tentar novamente',
});
}
}
})
.finally(() => setSubmitting(false));
},
});
const AssociateForm = props => {
const {
values,
touched,
errors,
handleSubmit,
setFieldValue,
setFieldTouched,
navigation,
isSubmitting,
} = props;
const renderItem = () => {
return (
<FormField
validateStatus={getValidateStatus('associate')}
error={getError('associate')}
>
<ItemInput
placeholder="Nome e sobrenome..."
onChangeText={text => {
setFieldValue('associate', text)
}}
onBlur={() => setFieldTouched('associate')}
initialValue={values.associate}
maxLength={32}
/>
</FormField>
)
}
const pagination = () => {
return (
<Pagination
dotsLength={3}
activeDotIndex={0}
containerStyle={{ backgroundColor: 'transparent' }}
dotStyle={{
width: 10,
height: 10,
borderRadius: 5,
marginHorizontal: 8,
backgroundColor: '#a18037'
}}
inactiveDotStyle={{
// Define styles for inactive dots here
}}
inactiveDotOpacity={0.4}
inactiveDotScale={0.6}
/>
);
}
const getValidateStatus = param => {
return errors[param] && touched[param]
? 'error'
: touched[param]
? 'success'
: '';
};
const getError = param => {
return errors[param] && touched[param] ? errors[param] : '';
};
return (
<View style={styles.container}>
<Text style={styles.title}>
Responda o questionário
</Text>
<Text style={styles.subtitle}>
{`Para ser um sócio Fiduc você precisa responder a este questionário e entraremos em contato para uma entrevista`}
</Text>
<View>
{ renderItem() }
{ pagination() }
</View>
<Button
primary
style={styles.submitButton}
onPress={ () => { navigation.navigate('NewAssociateSuccessScreen') }}
disabled={isSubmitting}
loading={isSubmitting}
>
<Text
style={[
styles.submitButtonText,
isSubmitting && { color: colors.secondary_text },
]}
uppercase={false}
>
Receber Indicação
</Text>
</Button>
</View>
);
};
export default withNavigation(withApollo(enhancer(AssociateForm)));
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
},
submitButton: {
height: moderateScale(20),
borderRadius: 0,
justifyContent: 'center',
marginTop: moderateScale(50),
paddingHorizontal: 48,
alignSelf: 'center',
},
submitButtonText: {
color: colors.button_text,
fontSize: moderateScale(18),
textAlign: 'center',
alignSelf: 'center',
},
whiteText: {
color: colors.secondary_text,
},
title: {
color: colors.text,
fontSize: moderateScale(23),
textAlign: 'center',
marginBottom: 8
},
subtitle: {
color: colors.text,
fontSize: moderateScale(12),
textAlign: 'justify',
marginBottom: 30
},
description: {
color: colors.secondary_text,
fontSize: moderateScale(16),
textAlign: 'center',
paddingVertical: moderateScale(10),
},
wrapper: {
}
});
package.json
{
"name": "fidelidade-app",
"version": "0.1.0",
"private": true,
"devDependencies": {
"babel-eslint": "^8.2.3",
"eslint": "^4.19.1",
"eslint-config-react-app": "^2.1.0",
"eslint-config-universe": "git+https://git#github.com/expo/eslint-config-universe",
"eslint-plugin-babel": "^5.1.0",
"eslint-plugin-flowtype": "^2.46.3",
"eslint-plugin-import": "^2.11.0",
"eslint-plugin-react": "^7.8.2",
"jest-expo": "26.0.0",
"prettier": "^1.12.1",
"react-native-scripts": "1.13.2",
"react-test-renderer": "16.3.0-alpha.1"
},
"main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
"scripts": {
"start": "react-native-scripts start",
"eject": "react-native-scripts eject",
"android": "react-native-scripts android",
"ios": "react-native-scripts ios",
"test": "jest",
"postinstall": "patch -p0 < apollo.patch || true",
"lint": "eslint ."
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"apollo-boost": "^0.1.4",
"axios": "^0.18.0",
"expo": "^27.0.0",
"formik": "^0.11.11",
"graphql": "^0.13.2",
"graphql-tag": "^2.9.1",
"moment-timezone": "^0.5.17",
"native-base": "^2.4.2",
"react": "16.3.1",
"react-apollo": "^2.1.3",
"react-native": "https://github.com/expo/react-native/archive/sdk-27.0.0.tar.gz",
"react-native-datepicker": "^1.7.2",
"react-native-easy-grid": "^0.1.17",
"react-native-gesture-password": "^0.3.4",
"react-native-maps-directions": "^1.6.0",
"react-native-masked-text": "^1.7.2",
"react-native-modal": "^6.1.0",
"react-native-scrollable-tab-view": "^0.8.0",
"react-native-snap-carousel": "^3.7.3",
"react-native-svg": "^6.5.2",
"react-native-swiper": "^1.5.13",
"react-navigation": "^2.0.1",
"react-navigation-fluid-transitions": "^0.2.6",
"yup": "^0.24.1"
}
}