I have a problem.
My App work right now but not like how I want.
App.js
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: true,
};
}
componentDidMount() {
fetch('https://reactnative.dev/movies.json')
.then((response) => response.json())
.then((json) => {
this.setState({ data: json.movies });
})
.catch((error) => console.error(error))
.finally(() => {
this.setState({ isLoading: false });
});
}
render() {
const { data, isLoading } = this.state;
const goToPageTwo = () => Actions.sw({text: 'Hello World!'});
return (
<View style={{ flex: 1, padding: 24 }}>
{isLoading ? <ActivityIndicator/> : (
<FlatList
data={data}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<TouchableOpacity onPress={() => { Actions.hp({text: item.id}) }}>
<Text>{item.title}</Text>
</TouchableOpacity>
)}
/>
)}
</View>
);
}
};
index.js / Route.js in my case sm.js
import app from './App';
import sw from './StarWars'
import bttf from './BacktotheFuture'
import hP from './handlePage';
import tM from './theMatrix';
import iN from './Inception';
const SceneManager = () => (
<Router>
<Scene>
<Scene key='home'
component={app}
title='BTour'
initial
/>
<Scene key='sw'
component={sw}
title='star wars'
/>
<Scene key='hp'
component={hP}
title='BTour'
/>
<Scene key='bttf'
component={bttf}
title='Back to the future'
/>
<Scene key='tM'
component={tM}
title='MAtrix'
/>
<Scene key='iN'
component={iN}
title='Inception'
/>
</Scene>
</Router>
)
export default SceneManager;
and my Handlepage.js
import StarWars from './StarWars';
import BTTF from './BacktotheFuture';
import TM from './theMatrix';
import IN from './Inception';
export default class handlePage extends Component {
renderElement() {
if(this.props.text ==1) {
return <StarWars/>
}
if (this.props.text ==2) {
return <BTTF/>
}
if (this.props.text ==3) {
return <TM/>
}
if(this.props.text == 4) {
return <IN/>
}
return null;
}
render(){
return(
this.renderElement()
)
}
};
NOW MY PROBLEM:
I want to use the Scene what I have defined in my Router class. For example when I press the first button in the Home Screen then "Star Wars" will be open but not the Component what I write in the route class.
Can I take the Component Scene from Route.js to the HandlePage.js in the If-Statemant OR can I put the If Statemant in the Router class.
Right now only the script in the IF-Statemant will open.
I don't think defining handlePage as class is necessary, you can just declare a function to navigate to your scene depending on item.id
Handlepage.js
import { Actions } from 'react-native-router-flux';
export const navigateByItemId = (id) => {
switch (id) {
case 1:
Actions.jump('sw');
break;
case 2:
Actions.jump('bttf');
break;
case 3:
Actions.jump('tM');
break;
default:
Actions.jump('iN');
}
};
And in App.js you can call this utility function to decide where to navigate
import { navigateByItemId } from './Handlepage';
...
<TouchableOpacity onPress={() => { navigateByItemId(item.id) }}>
<Text>{item.title}</Text>
</TouchableOpacity>
You can delete handlePage declaration in your router:
<Scene key='hp' //you can delete this code
component={hP}
title='BTour'
/>
Related
I have 2 components named A and B, In B I have a list of Languages to be selected and updated in component A. I am using Redux for state management when I change the Language from the list I can see that the states are updated(using redux-logger to get logs). But the problem is when I go back to Component A using react-navigation the updated state value is not updated I can see only the old value of state only
ScreenA.js
class ScreenA extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedLanguage: this.props.state.defaultLangName
}
}
render(
return (
<Container>
<Content style={{ backgroundColor: item.backgroundColor }}>
<View style={styles.logoContainer}>
<Text>test page</Text>
</View>
<View style={styles.cardParent}>
<View style={styles.card}>
<Item style={styles.listItem}>
<Button transparent style={styles.contentChecked} onPress={() => this._openLang()}>
<Text style={styles.listbtn}>{this.state.selectedLanguage}</Text>
<Icon name='ios-arrow-forward' style={styles.iconChecked}/>
</Button>
</Item>
</View>
</View>
</Content>
</Container>
);
)
}
export default connect(
state => ({ state : state.introauthenticate }),
dispatch => ({
actions: bindActionCreators(introActions, dispatch)
})
)(ScreenA);
ScreenB.js
class ScreenB extends Component {
constructor(props){
super(props);
this.state = {
langChecked: '0'
};
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#999",
}}
/>
);
}
_selectLanguage (val, name){
this.setState({ langChecked: val });
this.props.actions.changeLanguage(val,name, this.props.navigation.navigate);
//this.props.navigation.navigate('Intro');
}
renderItem = (item )=> {
return(
<TouchableHighlight
style={styles.boxSelect}
underlayColor="transparent"
onPress={() => this._selectLanguage(item.Value, item.Name)}
>
<View style={styles.contentChecked}>
<Text style={styles.item} > {item.Name} </Text>
{this.state.langChecked === item.Value && <Icon name="ios-checkmark-circle" style={styles.iconChecked}/>}
</View>
</TouchableHighlight>
)
}
render() {
return (
<Container>
<Header>
<Left>
<Button transparent onPress={() => this.props.navigation.goBack()}>
<Icon name='ios-arrow-back' />
</Button>
</Left>
<Body>
<Title>Languages</Title>
</Body>
<Right />
</Header>
<Content>
<FlatList
data={ langs }
keyExtractor={(item) => item.Value}
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem={({item}) => this.renderItem(item)}
/>
</Content>
</Container>
);
}
}
export default connect(
state => ({ state: state.introauthenticate }),
dispatch => ({
actions: bindActionCreators(introActions, dispatch)
})
)(ScreenB);
reducer.js
export const CHANGE_LANGUAGE = "CHANGE_LANGUAGE";
export function changeLanguage(langValue,langName,navigateTo) { // Fake authentication function
return async dispatch => {
try {
if (langValue && langName) { //If the email and password matches
const session = { langValue : langValue,langName:langName } // Create a fake token for authentication
setTimeout(() => { // Add a delay for faking a asynchronous request
dispatch(setLanguage(session)) // Dispatch a successful sign in after 1.5 seconds
navigateTo('Intro') // If successfull login navigate to the authenticated screen
}, 1500)
}
} catch (err) { // When something goes wrong
console.log(err)
}
};
}
function setLanguage(lang){
return {
type: types.CHANGE_LANGUAGE,
data: {
lang: lang
}
};
}
const initialsliderState = {
defaultLang:'en',
defaultLangName:'English',
};
export default function introauthenticate(state = initialsliderState, action = {}) {
switch (action.type) {
case types.CHANGE_LANGUAGE:
return {
...state,
defaultLang: action.data.lang.langValue,
defaultLangName: action.data.lang.langName,
};
default:
return state;
}
}
Logger:
LOG %c prev state "introauthenticate": {"defaultLang": "nl", "defaultLangName": "Deutsch", "isAuthSlider": false, "requestingsliderRestore": false}
LOG %c action {"data": {"lang": {"langName": "English", "langValue": "en"}}, "type": "CHANGE_LANGUAGE"}
LOG %c next state "introauthenticate": {"defaultLang": "en", "defaultLangName": "English", "isAuthSlider": false, "requestingsliderRestore": false}}
You are initializing the state of ScreenA with a value passed as a prop and never update it. As you are using redux to store the current language you do not need any state in ScreenA. When you connect a component you pass it the relevant data from your store as props. It seems like you are trying to "override" the state by passing it in as state but that does not update the state as it will be in this.props.state rather then in this.state. What you need to do is to just pass the language as a prop to ScreenA:
export default connect(
state => ({ selectedLanguage : state.introauthenticate.defaultLang }),
dispatch => ({
actions: bindActionCreators(introActions, dispatch)
})
)(ScreenA);
and then read the selected language from props:
<Text style={styles.listbtn}>{this.props.selectedLanguage}</Text>
When you update your store the component will re-render with the new language. You do not need any additional state in the component itself for data that you have in your redux store.
I have a fullscreen image I would like to display when my app state is loading. How can set this up?
I would like to implement something like this:
if (videos == "") {
return (
<View style={styles.imageContainer}>
<Image
style={styles.image}
source={require("../assets/images/tc-logo.png")}
/>
</View>
);
}
My current app.js looks like this
export default class App extends React.Component {
runInitialAppStartActions = () => {
store.dispatch(fetchData());
};
render() {
return (
<ImageBackground
source={require("./assets/images/TC_background.jpg")}
style={styles.container}
>
<Provider store={store}>
<PersistGate
loading={null}
persistor={persistor}
onBeforeLift={this.runInitialAppStartActions}
>
<AppNavigator
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
</PersistGate>
</Provider>
</ImageBackground>
);
}
}
Sory, i can't write comment, i need 50 reputation for comments.So I'm writing as an answer.
Im new in react, maybe you can solve with componentDidMount() method.
You can look this question: Stop rendering of a component after componentDidMount()
You can simply do it like this. I just assumed that you have a state named videos.
import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import * as videoAction from '../actions/videoAction.js';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
videos: ''
};
}
async componentDidMount() {
await this.props.videoAction.getVideo();
this.setState({
videos: this.props.videoState.videos
});
}
runInitialAppStartActions = () => {
store.dispatch(fetchData());
};
render() {
const {videos} = this.state;
if (videos == "") {
return (
<View style={styles.imageContainer}>
<Image
style={styles.image}
source={require("../assets/images/tc-logo.png")}
/>
</View>
);
}else{
return (
<ImageBackground
source={require("./assets/images/TC_background.jpg")}
style={styles.container}
>
<Provider store={store}>
<PersistGate
loading={null}
persistor={persistor}
onBeforeLift={this.runInitialAppStartActions}
>
<AppNavigator
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
</PersistGate>
</Provider>
</ImageBackground>
);
}
}
}
const mapStateToProps = (state) => {
return {
videoState: state.videoState
};
};
const mapDispatchToProps = (dispatch) => {
return{
videoAction: bindActionCreators(videoAction, dispatch)
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
What I want to achieve is display the datas in other screen or another component with React Redux. I'm using the latest version of React Redux and Redux.
My problem is every time I want to display the data, or when I press the button (TouchableOpacity) in EventCreator.js it doesn't display. I tried to check all of my codes but I don't see any typo or any wrong codes.
Feel free to ask for more of my codes. Thank you!
UPDATE: I tried all codes to my another new project, but with RNNV1. So it might be some new codes for RNNv2 that is related to React Redux to change. I prefer to all viewers to focus check my codes about RNNv2 connected to React Redux. Thank you!
These are my codes:
App.js, all my Registered Screens.
import {Navigation} from 'react-native-navigation';
import React from 'react';
//Screens
import AuthScreen from './src/screens/Auth/Auth';
import EventMap from './src/screens/Map/Map';
import EventCreator from './src/screens/EventCreator/EventCreator';
import EventHome from './src/screens/Home/Home';
import EventPushScreen from './src/screens/EventPushScreen/EventPushSc';
//Redux
import { Provider } from 'react-redux';
import configureStore from './src/store/configureStore';
const store = configureStore();
//Register Screens
Navigation.registerComponentWithRedux("Event.AuthScreen", () => AuthScreen);
Navigation.registerComponentWithRedux("Event.Map", () => EventMap);
Navigation.registerComponent("EventCreator", () => (props) => (
<Provider store={store}>
<EventCreator {...props}/>
</Provider>
), () => EventCreator);
Navigation.registerComponent("EventHome", () => (props) => (
<Provider store={store}>
<EventHome {...props}/>
</Provider>
), () => EventHome);
//Start A App
Navigation.events().registerAppLaunchedListener(() => {
Navigation.setRoot({
root: {
stack: {
children: [{
component: {
name: "Event.AuthScreen",
}
}],
options: {
topBar: {
title: {
text: 'Welcome',
alignment: 'center'
}
}
}
}
}
});
});
This is my 1st Screen where the TextInput and Button (TouchableOpacity) is.
EventCreator.js
import EventInput from '../../components/EventInput';
class EventCreator extends Component {
eventAddedHandler = (eventName) => {
this.props.onAddEvent(eventName);
};
render() {
return (
<View style={styles.container}>
<EventInput onEventAdded={this.eventAddedHandler}/>
</View>
);
}
};
const mapDispatchToProps = dispatch => {
return {
onAddEvent: (eventName) => dispatch(addEvent(eventName))
};
};
export default connect(null, mapDispatchToProps)(EventCreator);
EventInput.js, This is my Component that is connected to EventCreate.js
class EventInput extends Component {
state = {
eventName: ""
};
eventNameChangedHandler = (val) => {
this.setState({
eventName: val
});
};
eventSubmitHandler = () => {
if (this.state.eventName.trim() === "") {
return;
}
this.props.onEventAdded(this.state.eventName);
};
render () {
return (
<View style={styles.inputAndButtonContainer}>
<TextInput
placeholder="Create your event"
value={this.state.eventName}
onChangeText={this.eventNameChangedHandler}
style={styles.textInputContainer}
/>
<TouchableOpacity onPress={this.eventSubmitHandler}>
<View style={styles.buttonContainer}>
<Text style={{color: 'black'}}>Add</Text>
</View>
</TouchableOpacity>
</View>
);
}
};
Home.js, this is where I want to display may Data or the FlatList.
class Home extends Component {
eventSelectedHandler = key => {
const selEvent = this.props.events.find(event => {
return event.key === key;
});
Navigation.push("EventHomeStack", {
component: {
name: "EventPushScreen",
passProps: {
selectedEvent: selEvent
},
options: {
topBar: {
title: {
text: selEvent.name
}
}
}
}
});
};
render() {
return (
<View>
<EventList
events={this.props.events}
onItemSelected={this.eventSelectedHandler}
/>
</View>
);
}
};
const mapStateToProps = state => {
return {
events: state.events.events
};
};
export default connect(mapStateToProps)(Home);
EventList.js, another Component connected to Home.js
import ListItem from './ListItem';
const eventList = (props) => {
return (
<FlatList
style={styles.listContainer}
data={props.events}
renderItem={(info) => (
<ListItem
eventName={info.item.name}
eventImage={info.item.image}
onItemPressed={() => props.onItemSelected(info.item.key)}
/>
)}
/>
);
};
export default eventList;
listItem.js, another Component connected to EventList.js
const listItem = (props) => (
<TouchableOpacity onPress={props.onItemPressed}>
<View style={styles.listItem}>
<Image resizeMode="cover" source={props.eventImage} style={styles.eventImage}/>
<Text>
{props.eventName}
</Text>
</View>
</TouchableOpacity>
);
export default listItem;
events.js (reducer)
import {ADD_EVENT, DELETE_EVENT} from '../actions/actionTypes';
const initialState = {
events: []
};
const reducer = (state = initialState, action) => {
switch(action.type) {
case ADD_EVENT:
return {
...state,
events: state.events.concat({
key: `${Math.random()}`,
name: action.eventName,
image: {
uri: "https://c1.staticflickr.com/5/4096/4744241983_34023bf303_b.jpg"
}
})
};
case DELETE_EVENT:
return {
...state,
events: state.events.filter(event => {
return event.key !== action.eventKey;
})
};
default:
return state;
}
};
export default reducer;
in parent Browse.js
import { usersFetch, onToggleFollow } from '../actions';
class Browse extends Component {
render() {
return (
<ListView
....
renderRow={(user) =>
<UserItem user={user}
onPress={() => this.props.onToggleFollow()}
/>}
/>
);
}
}
export default connect(mapStateToProps, { usersFetch, onToggleFollow })(Browse);
in the child UserItem.js
class UserItem extends Component {
render() {
followButton = <Button title='Follow' onPress={() => {
this.props.onToggleFollow();
}}/>;
return (
<View style={styles.cardContainerStyle}>
<View>
{ followButton }
</View>
</View>
);
}
}
in the action creator file:
export const onToggleFollow = () => {
console.log('onToggleFollow method!');
return (dispatch) => {
dispatch({ type: ON_TOGGLE_SUCCESS });
};
};
I get an error says: "this.props.onToggleFollow is not a function, this.props.onToggleFollow is undefined" in UserItem.js, any helps thanks!
Your issue is on this line:
onPress={() => { this.props.onToggleFollow(); }}
in UserItem. You passed in the function as onPress prop so you should be calling this.props.onPress instead.
I'm new to React Native.
I have a React Native app using the Redux framework. I'm using the Navigator component to handle navigation but this.props.navigator is undefined in component. How can I pass "this.props.navigator" to component?
I'm not able to find any good examples of how to do it correctly so I'm looking for some help and clarification.
index.anroid.js
...
import App from './app/app';
AppRegistry.registerComponent('RnDemo', () => App);
app.js
...
import App from './containers/app';
const logger = createLogger();
const createStoreWithMiddleware = applyMiddleware(thunk, logger)(createStore);
const store = createStoreWithMiddleware(rootReducer);
const rootApp = () => {
return (
<Provider store={store}>
<App />
</Provider>
)
}
export default rootApp;
containers/app.js
...
class App extends Component {
renderScene(route, navigator) {
let Component = route.component
return (
<Component navigator={navigator} route={route} />
)
}
configureScene(route) {
if (route.name && route.name === 'Home') {
return Navigator.SceneConfigs.FadeAndroid
} else {
return Navigator.SceneConfigs.FloatFromBottomAndroid
}
}
_selectPage(page) {
if(page === 'detail') {
this.props.navigator.push({
component: Detail,
name: 'Detail'
}) // **this.props.navigator.push is not a function**
}
}
render() {
const { navigator } = this.props;
console.log(navigator); // **>>>>>> Undefined**
return (
<View style={styles.container}>
<View style={styles.menu}>
<TouchableOpacity onPress={() => this._selectPage('detail')}><View style={styles.menuItem}><Text>Detail</Text></View></TouchableOpacity>
</View>
<View style={styles.content}>
<Navigator
ref='navigator'
style={styles.navigator}
configureScene={this.configureScene}
renderScene={this.renderScene}
initialRoute={{
component: Home,
name: 'Main'
}}
/>
</View>
</View>
)
}
}
renderScene(route, navigator) {
let Component = route.component
return (
// <Component navigator={navigator} route={route} />
<Component {...this.props} navigator={navigator} route={route} />
)
}
Try it