I am currently trying to learn Redux but I am having trouble managing the state with Redux. Right now I can use useState to manage the state and it works but can't figure it out using Redux. Right now my app is just trying to get a text entered in the input field and when the button is pressed it will add it to the flatlist state.
import { connect } from 'react-redux';
import {View,Text,Button,TextInput,FlatList,ScrollView,} from 'react-native';
import { useState } from 'react';
import { Add_Item } from '../redux/actions/index';
const mapStateToProps = (state) => {
return { tasks: state.reducer.tasks };
};
const mapDispatchToProps = { Add_Item };
function App({ tasks, Add_Item }) {
const [add, setAdd] = useState('');
return (
<ScrollView>
<View style={{paddingTop: 20}}>
<View style={{ border: '2px solid green', margin: 10 }}>
<TextInput
placeholder="Enter Value Here"
onChangeText={(add) => setAdd(add)}
/>
</View>
<View
style={{
padding: 3,
border: '2px solid green',
backgroundColor: 'green',
'border-radius': 15,
margin: 10,
}}>
<Button
title="Add Values to Flatlist"
onPress={() => Add_Item(add)}
color="green"
/>
</View>
<FlatList
data={tasks}
renderItem={({ item }) => (
<View>
<Text
style={{
borderBottomColor: 'grey',
borderBottomWidth: 1,
padding: 5,
}}>
{item.title}
</Text>
</View>
)}
/>
</View>
</ScrollView>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
my textreducer file:
import { ADD_ITEM } from '../actionType/index';
var initialState = {
tasks: [],
};
export default function (state = initialState, action) {
if (action.type == ADD_ITEM) {
return {...state,
tasks: [...state.tasks,{title:action.payload.title}]}
}
return state;
}
my store file:
import { configureStore } from "#reduxjs/toolkit";
import reducer from "../reducers/index";
export default configureStore({reducer});
My app.js :
import React, { useState } from 'react';
import { View } from 'react-native';
import {Provider} from 'react-redux';
import store from './redux/store/index';
import AddApp from './FlatListApp/index'
export default function App() {
return (
<Provider store={store}>
<AddApp/>
</Provider>
);
}
the problem is you are using Add_Item itself in both mapDispatchToProps and in App, you must rename the Add_Item in mapDispatchToProps and then use it in App:
import { connect } from 'react-redux';
import {View,Text,Button,TextInput,FlatList,ScrollView,} from 'react-native';
import { useState } from 'react';
import { Add_Item } from '../redux/actions/index';
const mapStateToProps = (state) => {
return { tasks: state.reducer.tasks };
};
const mapDispatchToProps = {addItemAction: Add_Item };
function App({ tasks, addItemAction }) {
const [add, setAdd] = useState('');
return (
<ScrollView>
<View style={{paddingTop: 20}}>
<View style={{ border: '2px solid green', margin: 10 }}>
<TextInput
placeholder="Enter Value Here"
onChangeText={(add) => setAdd(add)}
/>
</View>
<View
style={{
padding: 3,
border: '2px solid green',
backgroundColor: 'green',
'border-radius': 15,
margin: 10,
}}>
<Button
title="Add Values to Flatlist"
onPress={() => addItemAction(add)}
color="green"
/>
</View>
<FlatList
data={tasks}
renderItem={({ item }) => (
<View>
<Text
style={{
borderBottomColor: 'grey',
borderBottomWidth: 1,
padding: 5,
}}>
{item.title}
</Text>
</View>
)}
/>
</View>
</ScrollView>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
but I recommend you to use hooks instead of connect and it's recommended by the redux team to use redux toolkit.
Related
Let me summarize a lil bit, what I'm trying to do is when the news is clicked, a modal (in this case I used a library: react-native-modalize https://github.com/jeremybarbet/react-native-modalize) is presented with the respective details of the clicked news
In order for the content inside the modal to be dynamic, I used states to store the details, so whenever a click is registered on the news, a series of details is passed thru function parameters and store in the respective state
THE PROBLEM is that whenever a state on the top level is changed the whole component refresh itself, and it's causing problem like:
Scenario 1: when the user scroll until the end of the scroll view and pressed on one of the news, modal is brought up and because the state is being changed, the whole app refreshes and the scroll view jumps back to the top.
app.js
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { useRef, useState, useEffect } from 'react';
import { AppLoading } from 'expo'
import { StyleSheet, Text, View, FlatList, SafeAreaView, ScrollView, Image, TouchableOpacity } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { Modalize } from 'react-native-modalize';
import { Ionicons } from '#expo/vector-icons';
import { render } from 'react-dom';
import Header from './components/Header';
import NuaDaily from './components/Daily';
import Content from './components/Content';
import moment from "moment";
const HomeStackScreen = () => {
const [title, setTitle] = useState([])
const [author, setAuthor] = useState([])
const [publication, setPublication] = useState([])
const [imageUrl, setImageUrl] = useState([])
const [summary, setSummary] = useState([])
const modalizeRef = useRef(null);
const onOpen = (title, author, publication, imageUrl, summary) => {
modalizeRef.current?.open();
setTitle(title)
setAuthor(author)
setPublication(publication)
setImageUrl(imageUrl)
setSummary(summary)
};
return (
<>
<SafeAreaView style={styles.container}>
<ScrollView style={styles.scrollView}>
<View style={styles.container}>
<Header />
<NuaDaily modalize={onOpen} style={styles.nuadaily} />
<Content modalize={onOpen} />
</View>
</ScrollView>
</SafeAreaView>
<Modalize snapPoint={650} modalTopOffset={10} ref={modalizeRef} style={{ width: '100%', alignItems: 'center', justifyContent: 'center', padding: 20 }}>
<View style={{padding: 20}}>
<Image
style={{width: 350, height: 200, zIndex: 1000, borderRadius: 8, marginTop: 10}}
source={{ uri: `${imageUrl}` }}
/>
<Text style={styles.modalTitle}>{title}</Text>
<View style={styles.detailsBar}>
<Text style={styles.modalAuthor}>{author}</Text>
<Text style={styles.modalPublication}>{moment(publication).format("MM-DD-YYYY")}</Text>
</View>
<Text style={styles.modalSummary}>{summary}</Text>
</View>
</Modalize>
</>
)
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator
tabBarOptions={
{
activeTintColor: '#00B2FF',
inactiveTintColor: 'gray',
showLabel: false,
style: { height: 60, borderRadius: 0, backgroundColor: 'rgba(255, 255, 255, 0.85)'}
}
}
showLabel = {false}
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
if (route.name === 'Home') {
return <HomeIcon />
}
},
})}
>
<Tab.Screen name="Home"
component={
HomeStackScreen
} />
</Tab.Navigator>
</NavigationContainer>
);
}
});
Daily (index.js) (imported on app.js)
import React from 'react';
import { useState, useEffect } from 'react';
import {View, Text, FlatList, Image, ImageBackground, ScrollView, SafeAreaView, TouchableOpacity} from 'react-native';
import axios from 'axios';
import moment from "moment";
import * as Font from 'expo-font';
import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';
import styles from './style';
import Dot from '../../assets/images/dot.svg';
const nuaDaily = ( props ) => {
const Item = ({ title, author, publication, imageUrl, summary }) => (
<View style={styles.item}>
<TouchableOpacity onPress={()=>props.modalize(title, author, publication, imageUrl, summary)}>
<Image
style={{width: 210, height: 200, zIndex: 1000, borderRadius: 8, marginTop: 10}}
source={{ uri: `${imageUrl}` }}
/>
<Text style={ [styles.title, {fontFamily: 'Poppins'}]}>{title}</Text>
<View style={styles.bottomBar}>
<Text style={styles.author}>{author}</Text>
<Text style={styles.publication}>{moment(publication).format("MM-DD-YYYY hh:mm")}</Text>
</View>
</TouchableOpacity>
</View>
);
const renderItem = ({ item }) => {
if(moment(item.publication).isSame(moment(), 'day')){
return <Item title={item.title} author={item.newsSite} publication={item.publishedAt} imageUrl={item.imageUrl} summary={item.summary} />
}else{
// return <Item title={item.title} author={item.newsSite} publication={item.publishedAt} imageUrl={item.imageUrl} summary={item.summary} />
}
};
const [data, setData] = useState([])
useEffect(() => {
axios.get(APIURL)
.then((res) => {
setData(res.data)
})
.catch((err) => {
console.log(`error calling API ${err}`)
})
},[])
return (
<View style={styles.container}>
<View style={styles.containerTitle}>
<Dot style={styles.dot} />
<Text style={ [styles.PrimaryText , {fontFamily: 'Quicksand'}]}>NUA Daily</Text>
</View>
<FlatList
showsHorizontalScrollIndicator={false}
horizontal={true}
data={data}
renderItem={renderItem}
style={styles.flatList}
/>
</View>
)
}
export default nuaDaily;
Demo of the problem (Scenario 1)
App has all old code which I am upgrading to latest versions. It was using Redux for state management with StackNavigator. Since that is not supported, I am not able to understand how to migrate my existing redux actions, which were changing screens on various events.
An example action:
export const goToHome = () => ({
type: PUSH,
routeName: 'projectList',
});
Which earlier reached navReducer, which handled POPing and PUSHing of screens.
export default (state = initialState, action) => {
let nextState;
switch (action.type) {
case NAV_POP:
nextState = AppNavigator.router.getStateForAction(
NavigationActions.goBack(),
state
);
break;
...
Please suggest.
Thanks.
The navigationRef is used for the scenarios like this.
You can refer the documentation here
It states
Sometimes you need to trigger a navigation action from places where
you do not have access to the navigation prop, such as a Redux
middleware. For such cases, you can dispatch navigation actions from
the navigation container
Which exactly is your requirement, here we create a navigationref and use call the navigation methods from there.
The below is the code for a simple example, you can use the 'navigate' inside your reducer. Also you will have to move it to a separate file just like they've provided in the documetation.
import * as React from 'react';
import { View, Button, Text } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const navigationRef = React.createRef();
function navigate(name, params) {
navigationRef.current && navigationRef.current.navigate(name, params);
}
function Home() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button
title="Go to Settings"
onPress={() => navigate('Settings', { userName: 'Lucy' })}
/>
</View>
);
}
function Settings({ route }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Hello {route.params.userName}</Text>
<Button title="Go to Home" onPress={() => navigate('Home')} />
</View>
);
}
const RootStack = createStackNavigator();
export default function App() {
return (
<NavigationContainer ref={navigationRef}>
<RootStack.Navigator>
<RootStack.Screen name="Home" component={Home} />
<RootStack.Screen name="Settings" component={Settings} />
</RootStack.Navigator>
</NavigationContainer>
);
}
you can navigate through navigation container ref
you can call navigation().navigate("Settings") or navigation().goBack() in reducer
here is the demo of export navigation: https://snack.expo.io/#nomi9995/2eb7fd
App.js
import React,{useEffect} from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const navRef = React.createRef();
export const navigation=()=>{
return navRef.current && navRef.current
}
const TestComponent=()=> {
useEffect(()=>{
setTimeout(() => {
navigation().navigate("Settings")
setTimeout(() => {
navigation().goBack()
}, 3000);
}, 100);
})
return (
<View style={styles.container}>
<Text>TestComponent 1</Text>
</View>
);
}
const TestComponent2=()=> {
return (
<View style={styles.container}>
<Text>TestComponent 2</Text>
</View>
);
}
const RootStack = createStackNavigator();
export default function App() {
return (
<NavigationContainer ref={navRef}>
<RootStack.Navigator>
<RootStack.Screen name="Home" component={TestComponent} />
<RootStack.Screen name="Settings" component={TestComponent2} />
</RootStack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
reducder.js
import { navigation } from 'path of App.js';
export default (state = initialState, action) => {
let nextState;
switch (action.type) {
case NAV_POP:
nextState = navigation().goBack()
break;
How do I connect my page2.js and page3.js to my CounterApp.js page, so far i only got my page2 and page3 connected with a button, and i can go back and fore between these 2 pages, but i need a button for my CounterApp.js page
CounterApp.js ///////////////////////////////////////////////////////////////////////////////////
import {Image} from 'react-native';
import React, { Component } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity
} from "react-native";
import { connect } from 'react-redux'
class CounterApp extends Component {
render() {
return (
<View style={styles.container}>
<View style={{ flexDirection: 'row', width: 200, justifyContent: 'space-around' }}>
<TouchableOpacity onPress={() => this.props.increaseCounter()}>
<Text style={{ fontSize: 20 }}>Increase</Text>
</TouchableOpacity>
<Text style={{ fontSize: 20 }}>{this.props.counter}</Text>
<TouchableOpacity onPress={() => this.props.decreaseCounter()}>
<Text style={{ fontSize: 20 }}>Decrease</Text>
</TouchableOpacity>
</View>
<Image source={{uri: 'https://facebook.github.io/react/logo-og.png'}}
style={{width: 200, height: 200}} />
<View style={{ flexDirection: 'row', width: 200, justifyContent: 'space-around' }}>
<TouchableOpacity onPress={() => this.props.increaseCounter2()}>
<Text style={{ fontSize: 20 }}>Increase</Text>
</TouchableOpacity>
<Text style={{ fontSize: 20 }}>{this.props.counter2}</Text>
<TouchableOpacity onPress={() => this.props.decreaseCounter2()}>
<Text style={{ fontSize: 20 }}>Decrease</Text>
</TouchableOpacity>
</View>
<Image source={{uri: 'https://facebook.github.io/react/logo-og.png'}}
style={{width: 200, height: 200}} />
</View>
);
}
}
function mapStateToProps(state) {
return {
counter: state.counter,
counter2: state.counter2,
}
}
function mapDispatchToProps(dispatch) {
return {
increaseCounter: () => dispatch({ type: 'INCREASE_COUNTER' }),
decreaseCounter: () => dispatch({ type: 'DECREASE_COUNTER' }),
increaseCounter2: () => dispatch({ type: 'INCREASE_COUNTER2' }),
decreaseCounter2: () => dispatch({ type: 'DECREASE_COUNTER2' }),
}
}
export default connect(mapStateToProps, mapDispatchToProps )(CounterApp)
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
});
page2.js /////////////////////////////////////////////////////////////////////
import React, {Component} from 'react';
import {Button} from 'react-native';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const {navigate} = this.props.navigation;
return (
<>
<Button
title="Go to Jane's profile"
onPress={() => this.props.navigation.navigate('Profile', {name: 'Jane'})}
/>
</>
);
}
}
export default HomeScreen;
page3.js ///////////////////////////////////////////////////////////////////////////////////////
import React, {Component} from 'react';
import {Button} from 'react-native';
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const {navigate} = this.props.navigation;
return (
<>
<Button
title="Go to Jane's home"
onPress={() => this.props.navigation.navigate('Home', {name: 'Jane'})}
/></>
);
}
}
export default HomeScreen;
mainnav.js ////////////////////////////////////////////////////////////////////////////////////////
import HomeScreen from './page2'
import ProfileScreen from './page3'
import CounterScreen from './CounterApp'
import {createStackNavigator} from 'react-navigation-stack';
const MainNavigator = createStackNavigator({
Home: {screen: HomeScreen},
Profile: {screen: ProfileScreen},
counter: {screen: CounterScreen}
},{initialRouteName:"Home"});
export default MainNavigator;
I have 2 listview in my homepage (TodoDetail.js and TodoDetailChecked.js) and there is TouchableOpacity's in this listview's rows.. When I click this TouchableOpacity, I want to go to Profile.js page.
But the problem is when I click, it can not find props.navigation.navigate.
I tried to catch logs in componentDidMount but nothing about navigate.
componentDidMount() {
console.log(this.props);
}
Please help me...
Here is the code;
TodoDetail.js
import React, { Component } from 'react';
import { Card, Icon } from 'react-native-elements';
// import Checkbox from '../components/Checkbox';
import { Text, View, TouchableOpacity } from 'react-native';
import * as firebase from 'firebase';
import {
Menu,
MenuOptions,
MenuOption,
MenuTrigger,
} from 'react-native-popup-menu';
class TodoDetail extends Component {
componentDidMount() {
console.log(this.props.navigation.navigate('TodoDetail'));
}
clickText() {
const { todo } = this.props.todos;
// const { navigate } = this.props.navigation;
return (
<TouchableOpacity onPress={this.seeDetail.bind(this)} >
<Text numberOfLines={1}> {todo} </Text>
</TouchableOpacity>
);
}
seeDetail() {
const { navigate } = this.props.navigation;
navigate("Profile", { name: "Jane" });
console.log('click');
}
render() {
//Serverdan çekilenler
const uid = this.props.todos.uid;
const success = this.props.todos.success;
//Tarih olayları
const date = new Date();
const day = date.getDate();
const tomorrow = day + 1;
const year = date.getFullYear();
const month = date.getMonth();
//Style tanımlama
const { container, iconContainer, subContainer } = styles;
if (success === 0) {
return (
<Card>
<View style={container}>
<View style={iconContainer}>
<TouchableOpacity onPress={() => firebase.database().ref(`todos/personal/${uid}/success`).set(1)} >
<Icon name='check-box-outline-blank' />
</TouchableOpacity>
<View style={subContainer}>
{this.clickText()}
</View>
<View style={iconContainer}>
<Menu>
<MenuTrigger>
<Icon name='keyboard-arrow-down' />
</MenuTrigger>
<MenuOptions>
<MenuOption onSelect={() => firebase.database().ref(`todos/personal/${uid}/date`).set({ day, year, month })} >
<Text style={{ color: 'black' }} > Son Tarihi Bugün </Text>
</MenuOption>
<MenuOption onSelect={() => firebase.database().ref(`todos/personal/${uid}/date`).set({ day: tomorrow, year, month })} >
<Text style={{ color: 'black' }} > Son Tarihi Yarın </Text>
</MenuOption>
<MenuOption onSelect={() => firebase.database().ref(`todos/personal/${uid}/date`).remove()} >
<Text style={{ color: 'black' }} > Son Tarihi Kaldır </Text>
</MenuOption>
<MenuOption onSelect={() => firebase.database().ref(`todos/personal/${uid}`).remove()} >
<Text style={{ color: 'red' }} > Yapılacak İşi Sil </Text>
</MenuOption>
</MenuOptions>
</Menu>
</View>
</View>
</View>
</Card>
);
} else
if (success === 1) {
return (
null
);
}
}
}
Todolist.js
createDataSource({ studentsArray }) {
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.dataSource = ds.cloneWithRows(studentsArray.reverse());
}
changeScreen() {
this.setState({ screenSize: false });
}
changeScreenBack() {
this.setState({ screenSize: true });
}
renderRow(todos) {
return <TodoDetail todos={todos} />;
}
renderRow2(todos) {
return <TodoDetailChecked todos={todos} />;
}
render() {
// const { navigate } = this.props.navigation;
const { container, inputContainer, inputText } = styles;
if (!this.state.screenSize) {
return (
<View style={container} >
<View style={inputContainer} >
<Icon name={'add'} />
<TextInput
style={inputText}
underlineColorAndroid='transparent'
placeholder="Yapılacak iş ekle..."
placeholderTextColor="#FFFFFF"
value={this.props.todo}
onChangeText={todo => this.props.todoChanged(todo)}
/>
<Button
onPress={this.addToDo.bind(this)}
title="Ekle"
color="#841584"
accessibilityLabel="Learn more about this purple button"
/>
</View>
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
<ListView
enableEmptySections
dataSource={this.dataSource}
renderRow={this.renderRow}
/>
</View>
<View style={{ flex: 1 }}>
<View style={{ height: 1, backgroundColor: 'gray' }} />
<ListView
enableEmptySections
dataSource={this.dataSource}
renderRow={this.renderRow2}
/>
</View>
</View>
<Button
onPress={this.changeScreenBack.bind(this)}
title="Tamamlananları Gizle"
color="#841584"
/>
</View>
);
} else
if (this.state.screenSize) {
return (
<View style={container} >
<View style={inputContainer} >
<Icon name={'add'} />
<TextInput
style={inputText}
underlineColorAndroid='transparent'
placeholder="Yapılacak iş ekle..."
placeholderTextColor="#FFFFFF"
value={this.props.todo}
onChangeText={todo => this.props.todoChanged(todo)}
/>
<Button
onPress={this.addToDo.bind(this)}
title="Ekle"
color="#841584"
/>
</View>
<View style={{ flex: 1 }}>
<ListView
enableEmptySections
dataSource={this.dataSource}
renderRow={this.renderRow}
/>
<Button
onPress={this.changeScreen.bind(this)}
title="Tamamlananları Göster"
color="#841584"
/>
</View>
</View>
);
}
}
}
Router.js
import { StackNavigator } from 'react-navigation';
import Todolist from './src/Todolist';
import Profile from './src/Profile';
import TodoDetail from './components/TodoDetail';
import TodoDetailChecked from './components/TodoDetailChecked';
import TodoPage from './components/TodoPage';
const Router = StackNavigator({
Todolist: { screen: Todolist },
TodoDetail: { screen: TodoDetail },
Profile: { screen: Profile },
TodoDetailChecked: { screen: TodoDetailChecked },
TodoPage: { screen: TodoPage }
});
export default Router;
This problem about parent child problem.
Let's quotes from documentation:
It's important to note that this only happens if the screen is
rendered as a route by React Navigation (for example, in response to
this.props.navigation.navigate). For example, if we render
DetailsScreen as a child of HomeScreen, then DetailsScreen won't be
provided with the navigation prop, and when you press the
"Go to Details... again" button on the Home screen, the app will throw one of
the quintessential JavaScript exceptions "undefined is not an object".
To fix your problem is pass this.props.navigation to child component from higher component.
Let's do example:
App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import MyView from './MyView';
import { StackNavigator } from 'react-navigation';
import DetailsScreen from './DetailsScreen';
class App extends React.Component {
render() {
return (
<View style={styles.container}>
<MyView navigation={this.props.navigation} />
<Text>Open up App.js to start working on your app!</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default StackNavigator({
Home: {
screen: App,
},
Details: {
screen: DetailsScreen,
}
});
MyView.js
import React from 'react';
import { StyleSheet, Text, ListView } from 'react-native';
import TodoDetail from './TodoDetail';
export default class MyView extends React.Component {
constructor() {
super();
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.state = {
dataSource: ds.cloneWithRows(['todo 1', 'todo 2']),
};
}
renderRow(todos) {
return <TodoDetail todos={todos} navigation={this.props.navigation} />;
}
render() {
return (
<ListView
enableEmptySections
dataSource={this.state.dataSource}
renderRow={(rowData) => this.renderRow(rowData)}
/>
);
}
}
TodoDetail.js
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
export default class TodoDetail extends React.Component {
componentDidMount() {
// console.log(this.props.navigation.navigate('Details'));
}
render() {
return (
<View>
<Text>Todo detail</Text>
<Text>{this.props.todos}</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details', { itemDetail: this.props.todos })}
/>
</View>
);
}
}
DetailsScreen.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default class DetailsScreen extends React.Component {
componentDidMount() {
console.log(this.props.navigation);
}
render() {
const { params } = this.props.navigation.state;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Text>{ params.itemDetail }</Text>
</View>
);
}
}
so in here, you need to pass navigation={this.props.navigation} every child render. If you see MyView component pass navigation props <MyView navigation={this.props.navigation} />.
And inside of it <TodoDetail todos={todos} navigation={this.props.navigation} />, last TodoDetail will available this.props.navigation to access this.props.navigation.navigate.
I have a component for listing items, I want to add the function that can go to a different page, and that page has the detail about that item. Currently, this is my code for listing items.
import React, { Component } from 'react';
import { ScrollView } from 'react-native';
import axios from 'axios';
import CarDetail from './CarDetail';
const API_URL = 'http://localhost:3000';
class CarList extends Component {
state = { cars: [] };
componentWillMount() {
console.log('Mount');
axios.get(`${API_URL}/cars`)
.then(response => this.setState({ cars: response.data.cars }));
}
renderCars() {
return this.state.cars.map(car => <CarDetail key={car.id} car={car} />
);
}
render() {
console.log(this.state.cars);
return (
<ScrollView>
{this.renderCars()}
</ScrollView>
);
}
}
export default CarList;
and this is the code for describing items
import React from 'react';
import { Text, View, Image } from 'react-native';
import { Actions } from 'react-native-router-flux';
import Card from '../material/Card';
import CardSection from '../material/CardSection';
const CarDetail = ({ car }) => {
const imageURI = 'https://yt3.ggpht.com/-HwO-2lhD4Co/AAAAAAAAAAI/AAAAAAAAAAA/p9WjzQD2-hU/s900-c-k-no-mo-rj-c0xffffff/photo.jpg';
const { make, model } = car;
function showCarDetail() {
Actions.showCar();
}
return (
<Card>
<CardSection>
<View style={styles.containerStyle}>
<Image
style={styles.imageStyle}
source={{ uri: imageURI }}
/>
</View>
<View style={styles.headContentStyle}>
<Text
style={styles.headerTextStyle}
onPress={showCarDetail()}
>
{make}
</Text>
<Text>{model}</Text>
</View>
</CardSection>
<CardSection>
<Image
style={styles.picStyle}
source={require('./car.jpg')}
/>
</CardSection>
</Card>
);
};
const styles = {
headContentStyle: {
flexDirection: 'column',
justifyContent: 'space-around'
},
headerTextStyle: {
fontSize: 18
},
imageStyle: {
height: 50,
width: 50
},
containerStyle: {
justifyContent: 'center',
alignItems: 'center',
marginLeft: 10,
marginRight: 10
},
picStyle: {
height: 300,
flex: 1,
width: null
}
};
export default CarDetail;
How can I change my code for that? Can anyone give me an example?
You have to use some sort of navigation component. There are many out there, but personally I use the one that is built into React Native. https://facebook.github.io/react-native/docs/navigator.html