I want to position 2 components underneath each other. My component looks like this :
import React from 'react';
import {connect} from 'react-redux';
import {Text, StyleSheet, View, ListView, Switch, TextInput} from 'react-native';
import {List, ListItem} from 'native-base';
import SearchBar from '../shared/search-bar';
const mapStateToProps = (state) => {
return {
movies: state.movies.movies
};
};
const mapDispatchToProps = (dispatch) => {
return {};
};
const Component = ({movies}) => {
return (
<View style={styles.container}>
<SearchBar style={styles.searchBarContainer}/>
<List
style={styles.list}
dataArray={movies}
renderRow={movie => <ListItem><Text>{movie.title}</Text></ListItem>}
/>
</View>
);
};
let styles = StyleSheet.create({
container: {
flexDirection: 'column',
flex: 1,
},
searchBarContainer: {
flex: 0
},
list: {
flex: 1
}
});
export default connect(mapStateToProps, mapDispatchToProps)(Component);
For some reason, when they are rendered, the list is just rendered over the searchbar. Why does the flexDirection:'column' not position them underneath each other?
I feel like I'm missing something about the flexbox layout.
in your style.container, remove the flex entry but keep the flexDirection.
Related
I want to use hook to get and set the value of my component WITHOUT PROPS. I import the component and it lists the data returned from the request, ok, but when I use the hook to see the data it returns empty, as if it were another instance.
Initially I used the state of the parent component, but when I needed to change some value of my component, everything would re-render as it affected the state of the parent component, so I want to isolate the state in the child component and use it freely as a hook elsewhere .
How I would like to use:
import MyComp, { useMyHook } from '../../../components/MyComp';
const OtherComp = () => {
const { data } = useMyHook();
return(
<div>
<button type="button" onClick={() => console.log(data)}>
click test
</button>
<MyComp />
</div>
);
};
export default OtherComp;
Component render
Example1
Example2
But the click button log: [ ]
Without using external components/libs like redux and etc.
My custom hook:
src/useMyHook.ts
import { useState } from 'react';
export const useMyHook = () => {
const [data, setData] = useState<any[]>([]);
const addItem = (item: unknown) => {
setData([...date, item]);
};
return { data, setData, addItem};
};
export default useMyHook;
My main component:
src/MyComp.tsx
import {useEffect} from 'react';
import useMyHook from './useMyHook';
const MyComp = () => {
const { data, setData } = useMyHook();
const req = async() => {
const {values} = await anyRequest(); // to do any request
setData(values);
};
useEffect(() => { req() },[]);
return(
<div>
{data.map((item) => <p>{item.name}</p>)}
</div>
);
};
export { useMyHook };
export default MyComp;
src/index.tsx
import MyComp, { useMyHook } from './MyComp';
export default MyComp;
export { useMyHook };
To demonstrate my comment:
import React,{useState, createContext} from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import Constants from 'expo-constants';
import useMyHook from './useMyHook'
import Example1 from './Example1'
import Example2 from './Example2'
import OtherComp from './OtherComp'
import {Data, DataSetter} from './types'
type DContext = {
data:Data,
setData:DataSetter
}
export const DataContext = createContext({
data:[],
setData:()=>{}
} as DContext)
export default function App() {
const [data, setData] = useState<Data>([])
return (
<View style={styles.container}>
<DataContext.Provider value={{data,setData}}>
<Example1/>
<Example2/>
<OtherComp/>
</DataContext.Provider>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
import { useContext, useCallback } from 'react';
import { DataContext } from './App';
export const useMyHook = () => {
const { data, setData } = useContext(DataContext);
// wrapped in useCallback to prevent function from
// being recreated
const addItem = useCallback((item: unknown) => {
setData(prev=>[...prev, item]);
},[]);
return { data, setData, addItem };
};
export default useMyHook;
useMyHook usage:
import React, { useEffect } from 'react';
import { View, Button } from 'react-native';
import useMyHook from './useMyHook';
export default function Example1() {
const { data, addItem } = useMyHook();
return (
<View style={{ width: '100%' }}>
<Button
title="Add Item From Example 1"
onPress={() => {
addItem(Math.floor(Math.random() * 25) + ' From Example1');
}}
/>
</View>
);
}
A demo
I'm trying to access useTheme() directly from the styles
But so far my solution doesn't seem to work.
I'm not getting in error back.
Is there a way to do what I'm trying to do?
import { StyleSheet } from "react-native";
import { useTheme } from '#react-navigation/native'
export default function () {
const { colors } = useTheme();
const styles = GlobalStyles({ colors: colors })
return styles
}
const GlobalStyles = (props) => StyleSheet.create({
container: {
flex: 1,
backgroundColor: props.colors.backgroundColor,
},
})
Accessing style in component
import React from "react";
import GlobalStyles from "../globalStyles.js"
class Inventory extends React.Component {
render() {
return (
<View style={globalStyles.container}>
)
}
You have a couple of issues: you can only use a hook within a hook or a function component. So you could convert your global stylesheet into a hook:
import { StyleSheet } from "react-native";
import { useTheme } from '#react-navigation/native'
const getGlobalStyles = (props) => StyleSheet.create({
container: {
flex: 1,
backgroundColor: props.colors.backgroundColor,
},
});
function useGlobalStyles() {
const { colors } = useTheme();
// We only want to recompute the stylesheet on changes in color.
const styles = React.useMemo(() => getGlobalStyles({ colors }), [colors]);
return styles;
}
export default useGlobalStyles;
Then you can use the hook by converting your Inventory class component into a function component and using the new useGlobalStyles hook.
import React from "react";
import useGlobalStyles from "../globalStyles.js"
const Inventory = () => {
const globalStyles = useGlobalStyles();
return (
<View style={globalStyles.container}>
)
}
Am trying to start playing with React Native now. And I come from web development field.
Since start, am trying to organize my folder structure so that it would be easy for me to understand and make modifications later.
Right now the folder structure is as follows:
/screens
HomeScreen.js
ProfileScreen.js
/navigation
MainNavigation.js
App.js
... etc
Am using Expo CLI as this is my first time working on React Native.
/navigation/MainNavigation.js
import React from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import HomeScreen from '../screens/HomeScreen';
import ProfileScreen from '../screens/ProfileScreen';
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Profile: ProfileScreen,
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class Navigation extends React.Component {
render() {
return (
<AppContainer />
);
}
}
/screens/HomeScreen.js
import React from 'react';
import { StyleSheet, Text, View, Button, TouchableOpacity } from 'react-native';
export default function HomeScreen() {
return (
<View style={styles.container}>
<TouchableOpacity style={styles.blue_btn} onPress={() => this.props.navigation.navigate('Profile')}>
<Text style={styles.white_text}>Profile</Text>
</TouchableOpacity>
<Text>Open up App.js to start working on your app!</Text>
</View>
);
}
HomeScreen.navigationOptions = {
header: null,
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
blue_btn: {
backgroundColor: '#13baa8',
padding: 10,
},
white_text: {
color: 'white',
}
});
/screens/ProfileScreen.js
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
export default function ProfileScreen() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
</View>
);
}
ProfileScreen.navigationOptions = {
title: 'Profile',
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
App.js
import React from 'react';
import Navigation from './navigation/MainNavigation';
export default class App extends React.Component {
render() {
return (
<Navigation />
);
}
}
When I click on the Profile button in the HOME Screen, it is showing this message:
undefined is not an object(evaluating '_this.props.navigation')
Thank you
import React, { Component } from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import ScreenOne from './ScreenOne';
import ScreenTwo from './ScreenTwo';
const NavStack = createStackNavigator({
ScreenOne: {
screen: ScreenOne,
},
ScreenTwo: {
screen: ScreenTwo,
},
});
const App = createAppContainer(NavStack);
export default App;
I am trying to print text content of login.php into the screen via "var result", but the fetch function won't alter value of "var result". How can I set value of result from output of the fetch function?
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
StatusBar,
} from 'react-native';
import Logo from '../components/Logo';
import Form from '../components/Form';
import loginapi from '../apis/loginapi';
var result='noresult';
export default class Login extends Component<{}> {
render() {
login();
return (
<View style={styles.container}>
<Logo/>
<Form/>
<Text>
{result}
</Text>
<Text>
</Text></View>
);
}
}
function login() {
result = fetch('https://www.skateandstrike.com/loginsv/login.php').then((text) => {return text;});
}
const styles = StyleSheet.create({
container : {
backgroundColor:'#f05545',
flex: 1,
alignItems:'center',
justifyContent:'center',
}
});
function myFunction() {
this.setState({ showLoading: false });
}
This is not working too, using setState:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
StatusBar,
} from 'react-native';
import Logo from '../components/Logo';
import Form from '../components/Form';
import loginapi from '../apis/loginapi';
export default class Login extends Component<{}> {
constructor(){
super();
this.state = {
data:'NoData',
}
}
render() {
login();
return (
<View style={styles.container}>
<Logo/>
<Form/>
<Text>
{this.state.data}
</Text>
</View>
);
}
}
function login() {
fetch('https://www.skateandstrike.com/loginsv/login.php').then(data => this.setState(data));
}
const styles = StyleSheet.create({
container : {
backgroundColor:'#f05545',
flex: 1,
alignItems:'center',
justifyContent:'center',
}
});
function myFunction() {
this.setState({ showLoading: false });
}
Am I using setState in a wrong way? Thanks in advance for your help.
When using the fetch API, I'd recommend using a promise, and you parse it if you are setting the state.
React re-renders on state/props change.
sample code:
fetch(url)
.then(data => data.json()) // if needed
.then(data => this.setState(data))
remember to set state in the constructor.
In one of the components in my project, I export a constant integer and then use it as a value for height in StyleSheet. In one particular case, it is not working and I can't figure out why. I have extracted the minimum possible code to reproduce it.
In TopBar.js, I export NAVBAR_HEIGHT and import it in both Home.js and MyModal.js. While it works right in Home.js when I use it as value of height in StyeSheet, it doesn't work in MyModal.js. However, if I replace NAVBAR_HEIGHT with a hardcoded int value, it works. It also works if I use NAVBAR_HEIGHT inline instead of creating a StyleSheet and passing the styles.topbar object.
(I wanted to make an rnplay for this, but looks like it can't make multiple files and thus, I couldn't reproduce it.)
Here is the code, apologies for making it long. I've also pushed it to git here.
Home.js (root component)
import React from 'react';
import {
View, StyleSheet, TouchableHighlight
} from 'react-native';
import TopBar, { NAVBAR_HEIGHT } from './TopBar';
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = { showModal: false };
}
render() {
return (
<TouchableHighlight onPress={this.toggleModal}>
<View style={styles.view}>
<TopBar showModal={this.state.showModal}
onClose={this.toggleModal} />
</View>
</TouchableHighlight>
);
}
toggleModal = () => {
this.setState({ showModal: !this.state.showModal });
}
}
const styles = StyleSheet.create({
view: {
height: NAVBAR_HEIGHT,
backgroundColor: 'blue',
}
});
MyModal.js
import React, { Component } from 'react';
import {
StyleSheet,
View,
Modal,
Text,
} from 'react-native';
import { NAVBAR_HEIGHT } from './TopBar';
export default class MyModal extends Component {
render() {
return (
<Modal animationType={'slide'}
visible={this.props.visible}
style={styles.container}
onRequestClose={this.props.onClose}>
<View style={styles.topbar}>
<Text style={styles.text}>{NAVBAR_HEIGHT}</Text>
</View>
</Modal>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
topbar: {
backgroundColor: 'red',
height: NAVBAR_HEIGHT,
},
text: {
fontSize: 20
}
});
TopBar.js
import React, { Component } from 'react';
import {
View,
StyleSheet,
Platform,
Text,
} from 'react-native';
import MyModal from './MyModal';
export const NAVBAR_HEIGHT = Platform.OS === 'ios' ? 200 : 100;
export default class TopBar extends Component {
render() {
return (
<View style={styles.container}>
<Text>TEST</Text>
<MyModal visible={this.props.showModal}
onClose={this.props.onClose} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'green',
},
});
I might be making some silly mistake but I have spent way too much time on this one and I'm still clueless. Help.
The modules TopBar.js and MyModal.js have a circular dependency: TopBar imports MyModal, and MyModal imports TopBar. Because module resolution is synchronous, the imported value is undefined.
Extract the common dependency into its own module and reference it from both TopBar and MyModal.
Here's a simple reproduction:
a.js
import {b} from './b';
export const a = 'a';
console.log('A sees B as', b);
b.js
import {a} from './a';
export const b = 'b';
console.log('B sees A as', a);
main.js
import {a} from './a';
Outputs:
B sees A as undefined
A sees B as b