React native todo application - react-native

I need your help. Now I'm trying to create a todo application.I will try to make an application on the logic of pure react.The problem is that when I start typing input, I get an error: undefined is not an object (evaluating 'e.target.value).Please help me with this task. I will be very grateful to you
Tasks.js
import React, {useState} from "react";
import {FlatList, StyleSheet, Text, View} from "react-native";
import Task_Item from "./Task_Item";
import Form from "./Form";
export default function Tasks() {
const [tasks, setTasks] = useState([]);
const [input, setInput] = useState('');
let addTask = (myInput) => {
if (myInput) {
let newTask = {
id: Date.now(),
name: myInput
}
setTasks([...tasks, newTask])
}
}
let handleInput = (e) => {
setTasks(e.target.value)
}
return (<View style={styles.all_list}>
<FlatList data={tasks}
renderItem={({item}) => (<Task_Item keyExtractor={item => item.id} el={item}/>)}
/>
<Form addTask={addTask} inputValue={handleInput}/>
</View>)
}
Task_item.js
import React from "react";
import {StyleSheet, TouchableHighlight, Text, ScrollView} from "react-native";
export default function Task_Item({el}) {
return (<ScrollView>
<TouchableHighlight>
<Text>{el.name}</Text>
</TouchableHighlight>
</ScrollView>)
}
Form.js
import React from "react";
import {KeyboardAvoidingView, StyleSheet, Text, TextInput} from "react-native";
export default function Form({inputValue, addTask}) {
return (<KeyboardAvoidingView>
<TextInput
placeholder='Type Text...'
onChangeText={inputValue}
/>
<Text
onPress={addTask}
>+</Text>
</KeyboardAvoidingView>)
}

I see two things you could improve.
The onChangeText method directly passes you the text, so you should either pass the setInput to your inputValue Form prop, either change the onChangeText to the onChange.
Using onChangeText
Tasks
<Form addTask={addTask} inputValue={setInput} />
Form.js
<TextInput placeholder="..." onChangeText={inputValue} />
And therefore you can delete the handleInput method.
with onChange
Tasks
<Form addTask={addTask} inputValue={handleInput} />
Form.js
<TextInput placeholder="..." onChange={handleInput} />
The second thing is that you handleInput method is changing your tasks and not your input...
const handleInput = (e) => setInput(e.target.value)
Your addTask is not getting the input... You could change your method to this:
const addTask = () => {
if (input) setTasks([...tasks, { id: Date.now(), name: input }])
}

Related

How to fix an Objects are not valid as a React child Error?

I am very new to programming with React-native, and I was wondering if anyone could explain how I should fix this error? I was following along with a tutorial and had an error come up due to this section of code, even though it matched the tutorial code.
Here is the section of code:
import React, { createContext, useContext } from "react";
import * as Google from "expo-google-app-auth";
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const signInWithGoogle = async() => {
await Google.logInAsync
}
return (
<AuthContext.Provider
value={{
user: null,
}}
>
{children}
</AuthContext.Provider>
);
};
export default function useAuth() {
return useContext(AuthContext);
}
These other two sections may be relevant as well:
Root of the App:
import React from 'react';
import { Text, View, SafeAreaView, Button, Alert } from 'react-native';
import AuthProvider from "./hooks/useAuth";
import StackNavigator from "./StackNavigator";
import { NavigationContainer} from "#react-navigation/native";
// Function for creating button
export default function App() {
return (
<NavigationContainer>
<AuthProvider>
<StackNavigator />
</AuthProvider>
</NavigationContainer>
);
}
This is my code for the Login Screen:
import React from 'react';
import { View, Text } from 'react-native';
import useAuth from '../hooks/useAuth';
const LoginScreen = () => {
const { user } = useAuth();
console.log(user);
return (
<View>
<Text>
Login to the app
</Text>
</View>
);
};
export default LoginScreen
This is the error that appears:
Error: Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead.
I suggest you auth with firebase. it makes easier this things.

React call function and setstate when go back to a previous screen

I'm new in React's world
I have 2 screens : Stock and Barcode.
In Stock, i navigate to Barcode's screen.
When i scan a barcode, i go back to the previous screen I would like to set the input text with the barcode and call a function. In my example joinData();
The problem is to set the input text and call a function.
I tried examples and answers but i don't find or don't understand how to to that.
I tried something in componentDidUpdate() but it fails
Invariant Violation:Maximum update depth exceeded
Stock.js
import React, {useState} from "react";
import { ScrollView, TouchableWithoutFeedback, Dimensions, StyleSheet, FlatList, View, Alert, TouchableOpacity, TextInput } from 'react-native';
//galio
import { Block, Text, theme } from "galio-framework";
import { Button, Icon, Input } from "../components/";
export default class Stock extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
this.array = [];
this.state = {
arrayHolder: [],
Input_ITMREF: ''
};
}
// I tried this but it fails
componentDidUpdate() {
if (this.props.navigation.getParam('itmref') != 'undefined') {
this.setState({ Input_ITMREF: this.props.navigation.getParam('itmref')});
}
}
componentDidMount() {
this.setState({ arrayHolder: [...this.array] }) // RafraƮchit la liste
}
joinData = () => {
vxml = this.state.Input_ITMREF+" I do something";
}
Render() {
return (
<Block flex>
<Block row space="evenly">
<Block center>
<Input
placeholder='Code article'
onChangeText={data => this.setState({ Input_ITMREF: data })}
ref={this.myRef}
/>
</Block>
</Block>
<Block center>
<Button style={styles.button} onPress={() => this.props.navigation.navigate('Barcode')}>Barcode</Button>
<Text style={{ margin: 10 }}>Post: {this.props.navigation.getParam('itmref')}</Text>
</Block>
</Block>
);
}
}
And Barcode.js
import React, {} from 'react';
import { ScrollView, TouchableWithoutFeedback, Dimensions, StyleSheet, FlatList, View, Alert, TouchableOpacity, TextInput } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import { Button } from "../components/";
export default class Barcode extends React.Component {
static navigationOptions = {
header: null //hide the header bar
};
handleBarCodeScanned = ({ type, data }) => {
this.props.navigation.navigate("Stock", {
itmref: data
});
};
render() {
return (
<BarCodeScanner
onBarCodeScanned={this.handleBarCodeScanned}
style={styles.barcodeScanner}
/>
);
}
}
You can pass a state handler function as prop to Barcode screen and use that to set value for textInput in state.
in Stock(in state)
state = {
inputValue: ''
}
....
const setInputTextValue= (newValue) => {
this.setState({
inputValue: newValue
})
you pass this function as prop to Barcode scene and call it whenever you wanna set a new value(considering Stock scene is still mounted).
UPDATE: What is the proper way to update a previous StackNavigator screen?
also another solution i just saw: Updating State of Another Screen in React Navigation
You need to use WillFocus method(Included in react-navigation) when you comeback from Barcodepage to stockPage
componentDidMount(){
console.log("willFocus runs") initial start
const {navigation} = this.props;
navigation.addListener ('willFocus', async () =>{
console.log("willFocus runs") // calling it here to make sure it is logged at every time screen is focused after initial start
});
}
For More Information read this document
https://reactnavigation.org/docs/function-after-focusing-screen/

Is there an fix for FlatList that can pass a function?

I'm setting up a FlatList, and want it will show my component inside it.
I made a function "renderEpisodes" that include my component and I want to pass this function inside the FlatList that it will show me all my details that include in there.
This is my FlatList with all the code
import React, { Component } from 'react';
import { ScrollView, FlatList, Text, View, Image } from 'react-native';
import axios from 'axios';
import EpisodeDetail from './EpisodeDetail';
import { Spinner } from './Spinner';
class EpisodeList extends Component {
state = { episodes: [] };
componentWillMount() {
axios.get('http://api.tvmaze.com/shows/1/episodes')
.then(Response => this.setState({ episodes: Response.data }));
}
renderEpisodes() {
return this.state.episodes.map(episode =>
<EpisodeDetail key={episode.name} episode={episode} />
);
}
render() {
return (
<FlatList
{this.renderEpisodes()}
/>
);
}
}
export default EpisodeList;
I expect the output of the FlatList will show me all content of the function "renderEpisodes" because of its include all my component stuff that I want to show.
You can try the following,
import React, { Component } from 'react';
import { ScrollView, FlatList, Text, View, Image } from 'react-native';
import axios from 'axios';
import EpisodeDetail from './EpisodeDetail';
import { Spinner } from './Spinner';
class EpisodeList extends Component {
state = { episodes: [] };
componentWillMount() {
axios.get('http://api.tvmaze.com/shows/1/episodes')
.then(Response => this.setState({ episodes: Response.data }));
}
renderEpisodes(episode) {
return (
<EpisodeDetail key={episode.name} episode={episode} />
);
}
render() {
return (
<FlatList
data={this.state.episodes}
renderItem={({item}) => this.renderEpisodes(item)}
/>
);
}
}
export default EpisodeList;
renderEpisodes({item,index}) {
return <EpisodeDetail key={index} episode={item} />
}
......
<FlatList data={this.state.episodes} renderItem={this.renderEpisodes}/>

Cannot read property 'items' of undefined

I'm new on Jest + Enzyme and I been doing some test in my app, everything was good till I try to test onPress event in one of my components that renders a ScrollView that has a ListItem inside. The error is: Cannot read property 'items' of undefined
Below is my code:
List.js
import React from 'react';
import { Text, StyleSheet, Image, View, ScrollView, Alert} from 'react-native';
import { ListItem, Button, Card } from 'react-native-elements'
import {observer, inject} from 'mobx-react';
import {StackNavigator} from 'react-navigation';
#inject('ItemStore')
#observer
export default class List extends React.Component{
constructor(props){
super(props);
this.state = {
itemsSelected: [],
}
}
displayItem(item, index){
const {navigate} = this.props.navigation;
this.props.ItemStore.ItemStore.itemSelected(item);
navigate("OtherComp", {'index': index});
}
render(){
return(
<ScrollView>
{
this.props.ItemStore.items.length ?
this.props.ItemStore.items.map((item, i) => (
<ListItem roundAvatar avatar = {{uri: item.photo_uri}}
title = {item.name}
key = {i}
onPress = {this.displayItem.bind(this, item, i)}
onLongPress = {this.setitem.bind(this, i)}
containerStyle = {{ backgroundColor: this.state.itemsSelected.indexOf(i) >= 0 ? "#f1f1f1" : "#ffffff"}}
/>
)) : undefined
}
</ScrollView>
);
}
}
List.test.js
import 'react-native';
import React from 'react';
import Enzyme from 'enzyme';
import MyList from '../../components/list/List';
import {shallow} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import sinon from 'sinon';
import { ListItem } from 'react-native-elements'
const ItemStore = require('../../stores/ItemStore').default;
Enzyme.configure({adapter: new Adapter()});
describe('ItemList', () => {
it('click list item', () => {
const wrapper = shallow(<MyList ItemStore={ItemStore.ItemStore} />)
const render = wrapper.dive();
const displayItem = sinon.spy(MyList, "displayItem");
render.find(ListItem).forEach(child => {
child.simulate('onPress');
});
expect(displayItem.calledOnce).toBe(true);
});
});
I'm using multiple stores that's why the invoke it's store.store
Shouldn't this:
this.props.ItemStore.items.length
Be..
this.props.ItemStore.ItemStore.items.length ?

Navigation in React Router v4 Native Not Changing Scenes

I'm using React Router for a React Native app. Not sure what I'm missing here but I install react-router-native and require the history package, and setup a couple methods that just push a new route onto the stack but nothing happens. I console.log('clicked'); to check that it's firing and it is so not sure what's wrong.
import React, { Component } from 'react';
import { View } from 'react-native';
import Splash from './Splash';
import createHistory from 'history/createMemoryHistory';
const history = createHistory();
class SplashContainer extends Component {
goToLogin = () => {
history.push('/Login');
}
goToRegister = () => {
history.push('/SignUp');
}
render () {
console.log(history)
return (
<Splash
goToLogin={this.goToLogin}
goToRegister={this.goToRegister}
/>
);
}
}
export default SplashContainer;
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import { Button } from 'native-base';
import { Link } from 'react-router-native';
import PropTypes from 'prop-types';
const Splash = (props) => {
console.log(props)
return (
<View style={styles.container}>
<Button light block onPress={props.goToLogin}>
<Text>Login</Text>
</Button>
<Button dark block bordered style={{marginTop: 10}} onPress={props.goToRegister}>
<Text>Register</Text>
</Button>
</View>
);
}
Splash.propTypes = {
goToLogin: PropTypes.func.isRequired,
goToRegister: PropTypes.func.isRequired
}
export default Splash;
I don't know your Router config, but your methods should be:
goToLogin = () => {
const { history } = this.props
history.push('/Login');
}
history will passed down via props of component inside Router's stack.