Related
I would like to have a date input field in a react-native form and I installed React Native DateTimePicker with the command: expo install #react-native-community/datetimepicker
To get started I used the following component almost exactly as described in the documentation:
import DateTimePicker from '#react-native-community/datetimepicker';
import React, { useState } from 'react';
import { Button, View, Text } from 'react-native';
export default function Picker () {
const [date, setDate] = useState(new Date(1598051730000));
const [mode, setMode] = useState('date');
const [show, setShow] = useState(false);
const onChange = (event, selectedDate) => {
const currentDate = selectedDate;
setShow(false);
setDate(currentDate);
};
const showMode = (currentMode) => {
setShow(true);
setMode(currentMode);
};
const showDatepicker = () => {
showMode('date');
};
const showTimepicker = () => {
showMode('time');
};
return (
<View>
<View>
<Button onPress={showDatepicker} title="Show date picker!" />
</View>
<View>
<Button onPress={showTimepicker} title="Show time picker!" />
</View>
<Text>selected: {date.toLocaleString()}</Text>
{show && (
<DateTimePicker
testID="dateTimePicker"
value={date}
mode={mode}
is24Hour={true}
onChange={onChange}
/>
)}
</View>
);
}
Then imported in another component.
However I get the following error:
./node_modules/#react-native-community/datetimepicker/src/DateTimePickerAndroid.js:23
Module not found: Can't resolve './picker'
21 | validateAndroidProps,
22 | } from './androidUtils';
> 23 | import pickers from './picker';
24 |
25 | function open(props: AndroidNativeProps) {
26 | const {
./node_modules/#react-native-community/datetimepicker/src/androidUtils.js:6
Module not found: Can't resolve './picker'
4 | */
5 | import {ANDROID_DISPLAY, ANDROID_MODE, MIN_MS} from './constants';
> 6 | import pickers from './picker';
7 | import type {AndroidNativeProps, DateTimePickerResult} from './types';
8 | import {sharedPropsValidation} from './utils';
9 | import invariant from 'invariant';
This error shows up when importing this package in the web version of react-native. Since the picker doesn't work on web anyway the easiest workaround is to not import it on web.
The way to do that is to create a separate file for native code. If you have a DateTimePicker.jsx file then rename it to DateTimePicker.native.jsx, then create a new file named DateTimePicker.jsx with the content:
export default function Picker() {
return <Text>Picker does not work on web.</Text>
}
Now you can import DateTimePicker from "DateTimePicker" and the android/ios version will import the picker, while on web you will get the noop version.
Try to back version to 6.0.2
Seems it is the actual issue for some people: https://github.com/react-native-datetimepicker/datetimepicker/issues/626
UPD:
I've tried to run your example and it works. My package.json:
"dependencies": {
"expo": "~45.0.0",
"expo-status-bar": "~1.3.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-native": "0.68.2",
"react-native-web": "0.17.7",
"#react-native-community/datetimepicker": "6.1.2"
},
If it won't help, try to reinstall node_modules and clear cash: https://facebook.github.io/metro/docs/troubleshooting/
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'm developing a new app with RN and using TabNavigator from react-navigation library, the most basic example of TabNavigator only showing first Tab. I've read somewhere that it could be a bug and could be solved by downgrading react-navigation to 1.0.3 but it didn't work for me. How to solve it?
tab1
tab2
app.js
import React, { Component } from 'react';
import Dashboard from './screens/Dashboard';
import Profile from './screens/Profile';
// import {I18nManager} from 'react-native';
// import { Container, Header, Content, Footer, FooterTab, Button, Icon, Text, Badge, Tab, Tabs } from 'native-base';
import { TabNavigator, TabBarBottom } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
export default TabNavigator({
home: { screen: Dashboard },
profile: { screen: Profile },
nav: { screen: Dashboard },
},
{
navigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, tintColor }) => {
const { routeName } = navigation.state;
let iconName;
if (routeName === 'home') {
iconName = `ios-pulse${focused ? '' : '-outline'}`;
} else if (routeName === 'profile') {
iconName = `ios-person${focused ? '' : '-outline'}`;
}
// You can return any component that you like here! We usually use an
// icon component from react-native-vector-icons
return <Ionicons name={iconName} size={25} color={tintColor} />;
},
}),
tabBarOptions: {
activeTintColor: 'blue',
inactiveTintColor: 'gray',
},
tabBarComponent: TabBarBottom,
lazy: false,
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false,
}
);
Dashboard.js
import React, { Component } from 'react';
import { TouchableOpacity,
Title,
Subtitle,
Tile,
Divider,
ImageBackground,
Card,
Image,
View,
Caption,
GridRow,
ListView,
Screen
} from '#shoutem/ui';
// import I18n from 'react-native-i18n';
// import {I18nManager} from 'react-native';
// I18nManager.forceRTL(true);
export default class Dashboard extends Component {
constructor(props) {
super(props);
this.renderRow = this.renderRow.bind(this);
this.state = {
restaurants: [
{
'name': 'برنامه ۳۰ روزه هوازی',
'address': 'چربی سوزی | کاهش وزن',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-1.jpg' },
},
{
'name': 'تمرین سینه',
'address': 'افزایش قدرت و حجم عضلات سینه و فرم دهی به آن',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-2.jpg' },
},
{
'name': 'تمرین شکم',
'address': 'حاضرید که عضلات شکمتان را ورزیده و تکه کنید؟ حرکاتی که در زیر آمده، راهنمایی است که همیشه برای شما کافی و مفید خواهد بود.',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-3.jpg' },
},
{
'name': 'تمرین سینه',
'address': 'افزایش قدرت و حجم عضلات سینه و فرم دهی به آن',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-2.jpg' },
},
{
'name': 'تمرین شکم',
'address': 'حاضرید که عضلات شکمتان را ورزیده و تکه کنید؟ حرکاتی که در زیر آمده، راهنمایی است که همیشه برای شما کافی و مفید خواهد بود.',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-3.jpg' },
},
{
'name': 'تمرین ران پا',
'address': 'این یک تست است.',
'image': { 'url': 'https://shoutem.github.io/static/getting-started/restaurant-2.jpg' },
},
],
};
}
renderRow(rowData, sectionId, index) {
// rowData contains grouped data for one row,
// so we need to remap it into cells and pass to GridRow
if (index === '0') {
return (
<TouchableOpacity key={index}>
<ImageBackground
styleName="large"
source={{ uri: rowData[0].image.url }}
>
<Tile>
<Title styleName="md-gutter-bottom">{rowData[0].name}</Title>
<Subtitle styleName="sm-gutter-horizontal">{rowData[0].address}</Subtitle>
</Tile>
</ImageBackground>
<Divider styleName="line" />
</TouchableOpacity>
);
}
const cellViews = rowData.map((restaurant, id) => {
return (
<TouchableOpacity key={id} styleName="flexible">
<Card styleName="flexible">
<Image
styleName="medium-wide"
source={{ uri: restaurant.image.url }}
/>
<View styleName="content">
<Subtitle numberOfLines={3}>{restaurant.name}</Subtitle>
<View styleName="horizontal">
<Caption styleName="collapsible" numberOfLines={2}>{restaurant.address}</Caption>
</View>
</View>
</Card>
</TouchableOpacity>
);
});
return (
<GridRow columns={2}>
{cellViews}
</GridRow>
);
}
render() {
const restaurants = this.state.restaurants;
// Group the restaurants into rows with 2 columns, except for the
// first restaurant. The first restaurant is treated as a featured restaurant
let isFirstArticle = true;
const groupedData = GridRow.groupByRows(restaurants, 2, () => {
if (isFirstArticle) {
isFirstArticle = false;
return 2;
}
return 1;
});
return (
<ListView
data={groupedData}
renderRow={this.renderRow}
/>
);
}
}
Profile.js
import React, { Component } from 'react';
import { Container, Header, Content, Form, Item, Input, Label } from 'native-base';
// import I18n from 'react-native-i18n';
// import {I18nManager} from 'react-native';
// I18nManager.forceRTL(true);
export default class Profile extends Component {
render() {
return (
<Container>
<Header />
<Content>
<Form>
<Item floatingLabel>
<Label>نام</Label>
<Input />
</Item>
<Item floatingLabel last>
<Label>قد (سانتیمتر)</Label>
<Input />
</Item>
</Form>
</Content>
</Container>
);
}
}
package.json
"dependencies": {
"#shoutem/ui": "^0.23.4",
"native-base": "^2.4.2",
"react": "16.3.1",
"react-native": "0.55.3",
"react-native-vector-icons": "^4.6.0",
"react-navigation": "^1.0.3"
},
"devDependencies": {
"babel-jest": "22.4.3",
"babel-preset-react-native": "4.0.0",
"eslint": "^4.19.1",
"eslint-plugin-react": "^7.7.0",
"jest": "22.4.3",
"react-test-renderer": "16.3.1"
},
"jest": {
"preset": "react-native"
}
I've already tried latest version of react-navigation so its downgraded version you see in package.json
I've found solution to this, and I'm going to be as specific as I can for all the people out there that might face this!
First of all it's a problem with I18nManager.forceRTL(true);
the moment you use this line of code anywhere on your react-native code that its screen gonna get rendered, and on 2nd reload, the app the layout is being change to RTL, and it does not change even if you comment that line! You'll have to use I18nManager.forceRTL(false); and reload a couple of times to get back to normal ltr setup.
The thing is... some of us really need that RTL layout change like I thought I did! Well guess what react-navigation does not respect that, at least for now and in the TabNabigator dept.
So to sum it all up: RTL layout on RN will break your react-navigation's Tab Navigation! (as of the current version you can see in the packages.json above) The issue makes only the first that visible and for the others a bland tab shows, if you turn on the animation or swipe other tabs will show but tabs behave in a weird way, meaning the last tab is active when the first one is active and vice versa... middle tabs are never focused by the way.
So you should know you can't use tabbed navigation with RTL layout. I'll update this answer after this issue got a fix!
I have run it using react-native run-ios, and all the tabs display a different screen. If you are referring to the fact that the nav tab does not change when you click on it whilst on the home tab, both the home and nav tabs are using the Dashboard screen.
The following is my package.json file for this project:
{
"name": "a",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"react-native-code-push": "1.15.0-beta",
"#babel/core": "^7.0.0-beta.40",
"#shoutem/ui": "^0.23.4",
"eslint": "^3.19.0",
"native-base": "^2.4.2",
"react": "16.3.1",
"react-native": "0.55.3",
"react-native-vector-icons": "^4.6.0",
"react-navigation": "^1.5.11"
},
"devDependencies": {
"babel-jest": "22.4.3",
"babel-preset-react-native": "4.0.0",
"jest": "22.4.3",
"react-test-renderer": "16.3.1"
},
"jest": {
"preset": "react-native"
}
}
I want to change an icon of TabBarIOS and wrote the following codes, but become the error of Element type is invalid.
import React from 'react';
import { View, TabBarIOS } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import CommunicationTab from './components/communication_tab';
import WhereaboutsTab from './components/whereabouts_tab';
export default class App extends React.Component {
constructor() {
super();
this.state = {
selectedTab: 'WhereaboutsTab',
};
}
render() {
return (
<TabBarIOS selectedTab={this.state.selectedTab}>
<Icon.TabBarItem
title="whereabouts"
iconName='ios-home-outline'
selectedIconName='ios-home'
selected={this.state.selectedTab === 'WhereaboutsTab'}
onPress={() => {
this.setState({
selectedTab: 'WhereaboutsTab'
});
}}
>
<WhereaboutsTab />
</Icon.TabBarItem>
<Icon.TabBarItem
title="communication"
iconName='ios-settings-outline'
selectedIconName='ios-settings'
selected={this.state.selectedTab === 'CommunicationTab'}
onPress={() => {
this.setState({
selectedTab: 'CommunicationTab'
});
}}
>
<CommunicationTab />
</Icon.TabBarItem>
</TabBarIOS>
);
}
}
When use following codes, do not have any problem.
<Icon name="ios-home" />
It is a project of expo which I made in create-react-native-app, will this be related?
package.json
"dependencies": {
"expo": "^16.0.0",
"moment": "^2.18.1",
"react": "16.0.0-alpha.6",
"react-native": "^0.43.4",
"react-native-action-button": "^2.6.9",
"react-native-md-textinput": "^2.0.4",
"react-native-modal-datetime-picker": "^4.6.0",
"react-native-swipeout": "^2.1.1",
"react-native-vector-icons": "^4.1.1"
}
I think you have a typo there.
Try replacing Icon.TabBarItem to Icon.TabBarItemIOS instead.