react native function return value not showing - reactjs

i am using react native code but some how code not working. please let me check how i can fix. i am getting value from cache and trying to return & show value.
i tried lot some how code not working if someone has any idea please let me know
import React, { memo } from 'react';
import { Text, View, StyleSheet, AsyncStorage } from 'react-native';
import { theme } from "../core/theme";
class Dashdata extends React.Component{
constructor(){
super();
this.getDataName = this.getDataName.bind(this);
this.state = {
displayname: ''
};
}
getDataName = () => {
const displayname = '';
console.log('getting value from cachedd');
const loginName = AsyncStorage.getItem('#kidssafety:displayname')
.then((result)=>{
console.log(result);
return (
<Text>{result}</Text>
)
});
}
render(){
return(
<View>
<Text style={styles.header}>Welcome Data {this.getDataName()}</Text>
</View>
)
}
}
const styles = StyleSheet.create({
header: {
fontSize: 22,
color: theme.colors.primary,
fontWeight: "bold",
paddingVertical: 14,
flex: 1,
marginTop: 100,
width: '100%',
textAlign: 'left'
}
});
export default memo(Dashdata);

AsyncStorage returns a promise. So you have to wait until it resolves.
Use Async/await to fix your problem.
getDataName = async () => {
const loginName = await AsyncStorage.getItem('#kidssafety:displayname')
this.setState({
displayname: loginName
})
}
Now you can display your values inside render
<Text style={styles.header}>Welcome Data {this.state.displayname}</Text>
Important
Since you are using as getDataName as an arrow function, you don't have to bind it as
this.getDataName = this.getDataName.bind(this)
Hope this helps you. Feel free for doubts.

AsyncStorage.getItem returns a promise and by the time it resolves and returns a value, your render would have moved to the next line. Ideally you should store the result to the state and use it when ready. Then your component will look like.
import React, { memo } from 'react';
import { Text, View, StyleSheet, AsyncStorage } from 'react-native';
import { theme } from "../core/theme";
class Dashdata extends React.Component{
constructor(){
super();
this.getDataName = this.getDataName.bind(this);
this.state = {
displayname: '',
result: '' // add result here
};
}
getDataName = () => {
const displayname = '';
console.log('getting value from cachedd');
const loginName = AsyncStorage.getItem('#kidssafety:displayname')
.then((result)=>{
console.log(result);
this.setState({result}) // set result to state
});
}
render(){
const { result } = this.state
return(
<View>
{!!result && (<Text style={styles.header}>Welcome Data {result})</Text>}
</View>
)
}
}
const styles = StyleSheet.create({
header: {
fontSize: 22,
color: theme.colors.primary,
fontWeight: "bold",
paddingVertical: 14,
flex: 1,
marginTop: 100,
width: '100%',
textAlign: 'left'
}
});
export default memo(Dashdata);

Related

setState not toggle value in react native

i am having function that toggle the state variables value.
the initial value of the state variable is false
Here is my function...
expandLists(label){ // "label" is a state variable that passed as a string
let result = new Boolean();
console.log(this.state);
if(this.state.label){
result=false;
console.log('Result = false');
}
else{
result=true;
console.log('Result = true');
}
this.setState({[label]: result},console.log(this.state))
}
In the above expression at inital state the value is changed to false then it is not changing to true.
I have also tried.. the below method...
expandLists(label){
this.setState( preState => ({label: !this.preState.label}),console.log(this.state))
}
If you pass the label parameter as a string, then try this:
expandLists(label){ // "label" is a state variable that passed as a string
let result = new Boolean();
console.log(this.state);
if(this.state[label]){
result=false;
console.log('Result = false');
}
else{
result=true;
console.log('Result = true');
}
this.setState({[label]: result},console.log(this.state))
}
So the difference is in checking if the current value is truethy. In stead of using this.state.label, use this.state[label].
Check this way as you said "label" param type of string
if(this.state.label == "true"){
...
}
or
if(this.state[label]){
...
}
Easy way to achieve this is
toggleLabelValue = (label) => {
this.setState({ [label]: !this.state[label] }, () =>
console.log(this.state)
);
};
Try toggling state in this way:
import React from 'react';
import {
View,
Button,
} from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
label: false
}
}
changeLabel = (currentLabel) => {
this.setState({
label: currentLabel
});
};
toggleLabel = () => {
this.changeLabel(!this.state.label);
};
render() {
return (
<View>
<Button onPress={this.toggleLabel} title="Toggle Label" />
</View>
);
}
}
Here is another implementation using hooks:
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const [label, setLabel] = useState(false);
const toggleLable = () => {
let temp = label;
setLabel(!temp);
};
return (
<View style={styles.container}>
<TouchableOpacity
onPress={toggleLable}
style={[
styles.btn,
{ backgroundColor: label ? '#4f4' : '#f40' },
]}>
<Text style={styles.text}>{label? "TRUE": "FALSE"}</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
btn: {
width: 200,
height: 200,
borderRadius: 20,
justifyContent: "center"
},
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
alignItems: 'center',
},
text:{
fontSize: 40,
fontWeight: "bold",
color: "white",
textAlign: "center"
}
});
Screenshot:
You can play around with the code here: Toggle Button Example
this works for me using useState:
import React, { useState } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import SeparateModal from 'components/SeparateModal';
export default function Parent() {
const [modalVisible, setModalVisible] = useState(false);
return (
<View>
<SeparateModal
modalVisible={modalVisible}
setModalVisible = {setModalVisible}
/>
<TouchableOpacity>
<Text onPress = { () => setModalVisible(true) }>Open Modal</Text>
</TouchableOpacity>
</View>
)
}
components/SeparateModal:
export default function SeparateModal({ modalVisible, setmodalVisible }) {
return (
<Modal
visible={ modalVisible }
animationType="slide"
>
<View>
<TouchableOpacity>
<Text onPress = { () => setModalVisible(false) }>Close Modal</Text>
</TouchableOpacity>
</View>
</Modal>
);

Changing the style of "toggled" elements in a list, react-native

I'm having trouble changing the style of only one element in a list.
Below is my Main class, as well as StationDetails class, which is a component I've created to render the list elements one by one.
There is one line (Line 31) in the StationDetails I cant seem to figure out the problem with. I want to style the component based on whether or not the elements' ID is included in the activeStations list.
Here is the line:
style={activeStations.includes(stations.id) ? pressedStyle : buttonStyle}
Here is my Main class
import React, { Component } from "react"
import axios from "axios"
import { Text, View, ScrollView } from "react-native"
import StationDetails from "./StationDetails"
class Main extends Component {
constructor(props) {
super(props)
this.state = { stations: [], pressStatus: false, activeStations: [] }
this.handleClick = this.handleClick.bind(this)
}
componentWillMount() {
axios
.get("https://api.citybik.es/v2/networks/trondheim-bysykkel")
.then(response =>
this.setState({ stations: response.data.network.stations })
)
}
handleClick() {
this.setState({ pressStatus: !this.state.pressStatus })
}
renderStations() {
return this.state.stations.map(stations => (
<StationDetails
activeStations={this.state.activeStations}
handleClick={this.handleClick}
pressStatus={this.state.pressStatus}
key={stations.id}
stations={stations}
>
{stations.name}
</StationDetails>
))
}
render() {
return (
<ScrollView style={{ flex: 1, marginTop: 20 }}>
{this.renderStations()}
</ScrollView>
)
}
}
export default Main
And here is my StationDetails component.
import React from "react"
import { Text, View } from "react-native"
import Card from "./felles/Card"
import CardSection from "./felles/CardSection"
import Button from "./felles/Button"
const StationDetails = ({
stations,
handleClick,
pressStatus,
activeStations
}) => {
const {
headerTextStyle,
leftPartStyle,
rightPartStyle,
pressedStyle,
buttonStyle
} = styles
return (
<Card style={{ flex: 1, flexDirection: "row" }}>
<CardSection style={leftPartStyle}>
<Text style={headerTextStyle}>
{stations.name}
</Text>
<Text>
Free bikes: {stations.free_bikes}
</Text>
</CardSection>
<CardSection style={rightPartStyle}>
<Button
onPress={() => {
if (!activeStations.includes(stations.id)) {
activeStations.push(stations.id)
} else {
activeStations.splice(activeStations.indexOf(stations.id), 1)
}
}}
style={
activeStations.includes(stations.id) ? pressedStyle : buttonStyle
}
>
Abonner
</Button>
</CardSection>
</Card>
)
}
const styles = {
textStyle: {
fontSize: 14
},
leftPartStyle: {
flex: 3,
flexDirection: "column",
justifyContent: "space-between"
},
rightPartStyle: {
flex: 1
},
pressedStyle: {
backgroundColor: "green"
},
headerTextStyle: {
fontSize: 18
},
thumbnailStyle: {
height: 50,
width: 50
},
buttonStyle: {
backgroundColor: "#fff"
}
}
export default StationDetails
You are trying to set state of Main.activeStations from StationDetails which is not advisable. Few things to keep in mind
Main's activeStations is in it's local component level state.
You shouldn't be trying to mutate that from a child component.
Since you assign mutated activeStations state to Main.activeStations from StationDetails, ReactNative (RN) doesn't find a difference in state in it's reconciliation process so does not re-render StationDetails.
We need RN to re-render StationDetails so that it will show the correct style for the buttons etc.
Documentation on setState
This is how I would do it
Let Main render StationDetails
Get a callback from StationDetails on which station was selected
Let Main take care of mutating it's own internal state (activeStations)
By doing it this way,
StationDetails is responsible only for rendering a list of stations given the props and nothing else. It's a dumb component that renders a list.
Main is responsible for handling it's own internal state
Heres the result :
Main.js class
import React, { Component } from 'react';
import axios from 'axios';
import { ScrollView } from 'react-native';
import StationDetails from './StationDetails';
export default class App extends Component {
constructor(props) {
super(props);
this.onSelectStation = this.onSelectStation.bind(this);
this.state = {
stations: [],
pressStatus: false,
activeStations: []
};
}
componentWillMount() {
axios.get('https://api.citybik.es/v2/networks/trondheim-bysykkel')
.then(response => this.setState({ stations: response.data.network.stations }));
}
onSelectStation(stationKey) {
const { activeStations } = this.state;
const activeStationsEdit = activeStations;
if (!activeStations.includes(stationKey)) {
activeStationsEdit.push(stationKey);
} else {
activeStationsEdit.splice(activeStations.indexOf(stationKey), 1);
}
this.setState({ activeStations: activeStationsEdit });
}
renderStations() {
return this.state.stations.map((stations) =>
<StationDetails
activeStations={this.state.activeStations}
pressStatus={this.state.pressStatus}
key={stations.id}
stations={stations}
stationId={stations.id}
onSelectStation={this.onSelectStation}
>
{stations.name}
</StationDetails>
);
}
render() {
return (
<ScrollView style={{ flex: 1, marginTop: 20 }}>
{this.renderStations()}
</ScrollView>
);
}
}
StationDetails class
import React from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
const StationDetails = ({ stations, activeStations, stationId, onSelectStation }) => {
const { headerTextStyle, leftPartStyle, container, pressedStyle, buttonStyle } = styles;
return (
<View style={container}>
<View style={leftPartStyle}>
<Text style={headerTextStyle}>
{stations.name}
</Text>
<Text>
Free bikes: {stations.free_bikes}
</Text>
</View>
<TouchableOpacity
onPress={() => onSelectStation(stationId)}
style={activeStations.includes(stations.id) ? pressedStyle : buttonStyle}
/>
</View>
);
}
const styles = {
container: {
flex: 1,
flexDirection: 'row',
marginBottom: 10
},
leftPartStyle: {
flex: 3,
flexDirection: 'column',
justifyContent: 'space-between'
},
pressedStyle: {
backgroundColor: 'green',
flex: 1,
},
headerTextStyle: {
fontSize: 18
},
buttonStyle: {
backgroundColor: 'skyblue',
flex: 1,
}
};
export default StationDetails;

React native component life cycle: `ref` usage and `null` object

I have a parent component index.js
render() {
const { firstName, token } = this.props.user;
if (token && firstName) {
return (
<View style={{ flex: 1 }}>
<HomeRoot />
</View>
);
}
console.log('=== ELSE');
return (
<View style={{ flex: 1 }}>
<SplashScreen />
</View>
);
}
}
And a SplashScreen that shows while the user is not logged in:
// Methods imports.
import React from 'react';
import { View, Text, Image, TouchableOpacity, StyleSheet } from 'react-native';
import { connect } from 'react-redux';
import { Asset, AppLoading, Font, DangerZone } from 'expo';
import FadeInView from '../animations/FadeInView';
// Redux actions
import { signinUser } from '../../store/actions/actions';
const { Lottie } = DangerZone;
const styles = StyleSheet.create({
wrapper: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
// ...
});
function cacheImages(images) {
return images.map(image => {
if (typeof image === 'string') {
return Image.prefetch(image);
}
return Asset.fromModule(image).downloadAsync();
});
}
function cacheFonts(fonts) {
return fonts.map(font => Font.loadAsync(font));
}
class SplashScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
isReady: false
};
this.bgAnim = null;
}
setBgAnim(anim) {
// if (anim === null) {
// return;
// }
this.bgAnim = anim;
this.bgAnim.play();
}
async loadAssetsAsync() {
const imageAssets = cacheImages([
// ...
]);
const fontAssets = cacheFonts([{
'cabin-bold': CabinBold,
'league-spartan-bold': LeagueSpartanBold
}]);
await Promise.all([...imageAssets, ...fontAssets]);
}
render() {
if (!this.state.isReady) {
return (
<AppLoading
startAsync={this.loadAssetsAsync}
onFinish={() => this.setState({ isReady: true })}
/>
);
}
return (
<View style={styles.wrapper}>
<Lottie
ref={c => this.setBgAnim(c)}
resizeMode="cover"
style={{
position: 'absolute',
zIndex: 1,
left: 0,
top: 0,
width: '100%',
height: '100%',
}}
source={require('../../../assets/SPLASH_03.json')} // eslint-disable-line
/>
</View>
);t
}
}
export default connect(
null,
{ signinUser }
)(SplashScreen);
The signinUser calls facebookAuth and then store the fetched user profile and token in one unique dispatch.
At this point the index.js
token && firstName are true and the SplashScreen component should let his place to HomeRoot.
However it crashes on SplashScreen render method: ref={c => this.setBgAnim(c)}. If we remove this line, or check to discard c when c is null everything works as expected.
Why is c null at this stage in ref={c => this.setBgAnim(c)}?
How should I handle this problem in a better way than checking for null?
From docs:
React will call the ref callback with the DOM element when the component mounts, and call it with null when it unmounts. ref callbacks are invoked before componentDidMount or componentDidUpdate lifecycle hooks.
Knowing that at some points ref passed to callback will be a null, just do a check:
setBgAnim(anim) {
this.bgAnim = anim;
if(anim) {
this.bgAnim.play();
}
}
I don't think there is something wrong with such approach.

How to make a dynamic datasource in listview react native?

I don't know what happen to my code. I'm trying to create a Todo list. I'm using listview. I have two components the Todo and the AddTodo.
main component
import React, { Component } from 'react';
import { View, Text, TextInput, StyleSheet, ListView } from 'react-native';
import * as moment from 'moment';
import TodoList from '../compoents/TodoList';
import {TodoModel, ITodo} from '../models/TodoModel';
interface TodoProps{
todo: TodoModel;
ter:string;
}
interface TodoState{
dataSource: any;
myTodo: Array<ITodo>;
}
export default class Todo extends React.Component <TodoProps,TodoState>{
constructor(props:TodoProps) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => true});
this.state = {
dataSource: ds,
myTodo: []
};
}
componentWillMount = () => {
console.log(this.state.myTodo);
let data = {
title: this.props.ter
};
if (this.props.ter) {
this.state.myTodo.push(data);
}
this.setState({
dataSource: this.state.dataSource.cloneWithRows(this.state.myTodo),
myTodo: this.state.myTodo
});
}
render() {
return (
<View style={{marginTop: 60}}>
<ListView enableEmptySections={true} dataSource={this.state.dataSource} renderRow={(rowData) => <TodoList data={rowData} /> } />
</View>
)
}
}
this will view the list of todo that I add from the form
AddTodo component
import * as React from "react";
import { Alert, View, Text, StyleSheet, TextInput, TouchableOpacity } from 'react-native';
import {TodoModel} from '../models/TodoModel';
import { Actions} from 'react-native-router-flux';
interface TodoState{
todoText?: string;
}
interface TodoProps{
text: string;
}
export default class AddTodo extends React.Component <TodoProps,TodoState> {
constructor(props:TodoProps){
super(props);
this.state = {
todoText:" "
};
}
handleSubmit = () => {
Actions.todo({ter: this.state.todoText});
}
render() {
return (
<View style={{margin: 128, marginLeft: 15, marginRight:15}}>
<Text>ADD</Text>
<TextInput autoCorrect={false} style={styles.input} placeholder='Todo' onChangeText={(text) => this.setState({todoText:text})} value={this.state.todoText} />
<TouchableOpacity onPress={this.handleSubmit.bind(this)}>
<Text style={styles.button}>Submit</Text>
</TouchableOpacity>
</View>
)
}
}
const styles = StyleSheet.create({
button: {
backgroundColor: '#ccc',
color: 'white',
height: 40,
lineHeight: 30,
marginTop: 10,
textAlign: 'center',
alignSelf: 'stretch',
borderRadius: 5,
justifyContent: 'center',
alignItems: 'center',
},
container: {
},
input: {
borderColor: '#ededed',
borderRadius: 5,
borderWidth: 1,
height: 37,
alignSelf: 'stretch',
}
})
the issue here. When the time I add one todo. I was successfully added to the myTodo array, but when I add the second todo. It removes the first todo, and show the second todo. It doesn't push and add to the array. Why it happen that way? but if you have tutorial on how to do it. It will more great to study for it. I'm very interested to learn react native.
update
export default class App extends React.Component<Props, State> {
render() {
return (
<Router>
<Scene key="root">
<Scene key="todo" component={Todo} title="Todo" initial={true} onRight={() => Actions.addTodo({text: 'Hello World!'})}
rightTitle="Add"/>
<Scene key="addTodo" component={AddTodo} title="Add Todo" backTitle="Cancel" />
</Scene>
</Router>
);
}
}
Let try my code, hope it can help you.
Your "push" will mutate the state directly and that could potentially lead to error prone code, even if you are "resetting" the state again afterwards
You can find more here: Correct modification of state arrays in ReactJS
Edited:
rewrite handleSubmit function
handleSubmit = () => {
Actions.pop({refresh :
{ter: this.state.todoText}
});
}
Change componentWillMount to componentWillReceiveProps
componentWillReceiveProps = (nextProps) => {
console.log(this.state.myTodo);
let data = {
title: nextProps.ter
};
let todoList = this.state.myTodo
if (nextProps.ter) {
todoList.push(data);
}
this.setState({
myTodo: todoList
});
}
You can see my answer for a very similar issue:
React Native: Child ListView will not update after element in parent is changed
So in fact, in your case, you may simply do this:
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => true});
export default class Todo extends React.Component <TodoProps,TodoState>{
constructor(props:TodoProps) {
super(props);
this.state = {
dataSource: ds.cloneWithRows([]), // or put your initial data here
myTodo: []
};
}
Then, every time you want to update the list, just use ds.cloneWithRows(NEW_DATA)
componentWillMount() {
// ...
this.setState({
dataSource: ds.cloneWithRows(this.state.myTodo),
myTodo: this.state.myTodo
});
}
One more thing, for react's default functions in component's life cycle, they are bound automatically, so don't need to use componentWillMount = () => {}, just use componentWillMount()
This is just the way you should do, if errors still happen, please show here, then we may figure them out together, thanks

(React Native) Null is not an object

This is the portion of the code React Native is having trouble rendering:
You input {this.state.zip}.
Im a beginner and I was following a tutorial in "Learning React Native" yet he code in the book is not working.
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TextInput,
Image,
View
} from 'react-native';
class WeatherProject extends Component {
// If you want to have a default zip code, you could add one here
getInitialState() {
return ({
zip: ''
});
}
// We'll pass this callback to the <TextInput>
_handleTextChange(event) {
// log statements are viewable in Xcode,
// or the Chrome debug tools
console.log(event.nativeEvent.text);
this.setState({
zip: event.nativeEvent.text
});
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
You input {this.state.zip}.
</Text>
<TextInput
style={styles.input}
onSubmitEditing={this._handleTextChange}/>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
borderWidth: 2,
height: 40
}
});
AppRegistry.registerComponent('WeatherProject', () => WeatherProject);
[enter image description here][1]
In ES6 Classes (one where you are extending Component rather than using createClass), initial states are set with this.state = {zip: ''} in constructor.
So it would-be
class WeatherProject extends Component {
constructor(props){
super(props);
this.state = {
zip: ""
}
}
}
getInitialState is typically used with React.createClass. For defining a component as class, the following code should be in constructor:
getInitialState() {
return ({
zip: ''
});
}
constructor:
constructor() {
super();
this.state = {
zip: ''
}
}

Resources