I am trying to do a basic todo list however when I dispatch an action after pressing add it doesn't dispatch .
I've taken the dispatch(todo(todoList))out of every function and left it in the main ToDo component to do multiple calls on every letter typed into the search box and I can see an update in my redux store in Redux-dev tools so I know my todo works but It won't dispatch() when I try to submit. Please can someone help me .
This is my code:
import {useDispatch } from 'react-redux'
import { todo } from './action/todo'
const ToDo = () => {
const [todo, setTodo] = useState('')
const [todoList, setTodoList] = useState([])
const dispatch = useDispatch()
const handleSubmit = (id , todo) => {
const newTodoList = todoList.concat({ id: id, val: todo })
return (
setTodo(''),
todo.length === 0
? <Text/>
: setTodoList(newTodoList) // if I put the dispatch here it doesn't work either
)
}
return (
<View style={styles.addPhotoCont}>
<TextInput
placeholder={props.textInputPlaceholder}
onChangeText={props => setTodo(props)}
value={todo}
/>
<TouchableOpacity
onPress={() => handleSubmit(Date.now(), todo) && dispatch(todo(todoList))}>
<Text style={styles.addButton}>Add</Text>
</TouchableOpacity>
</View>
)
}
It looks like you set todo twice, once as an import, and the second time as state. When you call dispatch and pass in todo it is calling the state version.
You should put the dispatch in the handleSubmit function.
Also, looking at the handleSubmit function, the return will not work. You can only return one thing. You can place the other functions above the return statement.
Edit:
Code sample below:
import { useDispatch } from 'react-redux'
import { todo } from './action/todo'
const ToDo = (props) => {
const [todoInputValue, setTodoInputValue] = useState('')
const dispatch = useDispatch()
const handleSubmit = (todo) => {
dispatch(todo({id: Date.now(), val: todoInputValue}))
setTodoInputValue('')
}
return (
<View style={styles.addPhotoCont}>
<TextInput
placeholder={props.textInputPlaceholder}
onChangeText={value => setTodoInputValue(value)}
value={todoInputValue}
/>
<TouchableOpacity
onPress={() => handleSubmit(Date.now())}>
<Text style={styles.addButton}>Add</Text>
</TouchableOpacity>
</View>
)
}
Related
I have an input which passes its value to a useState on its parent.
That value gets passed to other component (Custom button).
There the input data gets validated and returns to the parent in another useState if there's an error and where ("e" = error in email, "p" = error in password, "ep" = error in email and password)
Then the border color of the input is set accordingly to that response, if there is an error it turns red, otherwise it turns white.
But it only works the second time i press the button (With which everything is supposed to start)
HELP!😣
const LoginScreen = () => {
const [email, setemail] = useState('');
const [password, setpassword] = useState('');
const [error, seterror] = useState('');
return (
<View style={styles.container}>
<Input
placeholder={"Correo :"}
setInputValue={value => setemail(value)}
color={
error.includes("e") ? '#FA8072' : 'white'
}
/>
<Input
placeholder={"Contraseña :"}
setInputValue={value => setpassword(value)}
color={
error.includes("p") ? '#FA8072' : 'white'
}
/>
<LoginButton data={{email: email, password: password}} setValue={value => {seterror(value)}}/>
</View>
)
}
=========================================
Input component
const Input = (props) => {
return (
<View style={styles.container}>
<Text style={styles.placeholder}>{props.placeholder}</Text>
<TextInput
style={[styles.input, {borderColor: props.color}]}
onChangeText={(value) => props.setInputValue(value)}
/>
</View>
)
}
=========================================
Button component
const LoginButton = (props) => {
const [inputError, setinputError] = useState('')
let validateData = () => {
if(!props.data.email && !props.data.password){
setinputError('ep')
}
else if(!props.data.email){
setinputError('e')
}
else if(!props.data.password){
setinputError('p')
}
else {
setinputError('')
}
}
return (
<TouchableOpacity style={styles.mainButton} onPress={() => {validateData(); props.setValue(inputError)}}>
<Text style={styles.mainButtonText}>Iniciar sesión</Text>
</TouchableOpacity>
)
}
Because you're trying to change state twice. Actually you don't need use state to pass value at LoginButton component. Try direct call instead.
const LoginButton = (props) => {
let validateData = () => {
if(!props.data.email && !props.data.password){
props.setValue("ep");
}
else if(!props.data.email){
props.setValue('e');
}
else if(!props.data.password){
props.setValue('p');
}
else {
props.setValue('');
}
}
return (
<TouchableOpacity style={styles.mainButton} onPress={() => validateData()}>
<Text style={styles.mainButtonText}>Iniciar sesión</Text>
</TouchableOpacity>
)
}
I'm training on react-native.
I'm trying to figure out how I can save data locally.
I have a to-do list and choose the person assigned to this task.
I would like to save the tasks that I add so that they are kept when I stop and restart the application for example. I was thinking of using async storage so I did it like this:
const storeData = async (task) => {
try {
await AsyncStorage.setItem('key', task)
} catch (e) {
// lance une erreur
} }
But it doesn't seem to be working.
Here is all of my code for this page. Could you please help me get my code working, and explain to me the behavior of the function in the process?
Thank you.
import React, {useState} from 'react';
import { KeyboardAvoidingView, Text, View, TextInput, TouchableOpacity, Keyboard, ScrollView } from 'react-native';
import Task from '../../Task';
import SelectDropdown from 'react-native-select-dropdown'
import styles from "../../../assets/styles"
export default function Trucs() {
const [task, setTask] = useState();
const [taskItems, setTaskItems] = useState([]);
const users = ["Jibé", "Charly"]
const handleAddTask = () => {
Keyboard.dismiss();
setTaskItems([...taskItems, task])
setTask(null);
}
const storeData = async (task) => {
try {
await AsyncStorage.setItem('key', task)
} catch (e) {
// lance une erreur
}
}
const completeTask = (index) => {
let itemsCopy = [...taskItems];
itemsCopy.splice(index, 1);
setTaskItems(itemsCopy)
storeData(task)
}
return (
<View style={styles.wrap}>
{/* Added this scroll view to enable scrolling when list gets longer than the page */}
<ScrollView
contentContainerStyle={{
flexGrow: 1
}}
keyboardShouldPersistTaps='handled'
>
{/* Today's Tasks */}
<View style={styles.tasksWrapper}>
<Text style={styles.sectionTitle}>Trucs à faire</Text>
{/* This is where the tasks will go! */}
{
taskItems.map((item, index) => {
return (
<TouchableOpacity key={index} onPress={() => completeTask(index)}>
<View>
<Task text={item}/>
<SelectDropdown
data={users}
onSelect={(selectedItem, index) => {
console.log(selectedItem, index)
}}
buttonTextAfterSelection={(selectedItem, index) => {
// text represented after item is selected
// if data array is an array of objects then return selectedItem.property to render after item is selected
return selectedItem
}}
rowTextForSelection={(item, index) => {
// text represented for each item in dropdown
// if data array is an array of objects then return item.property to represent item in dropdown
return item
}}/>
</View>
</TouchableOpacity>
)
})
}
</View>
</ScrollView>
{/* Write a task */}
{/* Uses a keyboard avoiding view which ensures the keyboard does not cover the items on screen */}
<KeyboardAvoidingView
// behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.writeTaskWrapper}
>
<TextInput style={styles.input} placeholder={'Rajouter un truc à faire'} value={task} onChangeText={text => setTask(text)} />
<TouchableOpacity onPress={() => handleAddTask()}>
<View style={styles.addWrapper}>
<Text style={styles.addText}>+</Text>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
</View>
);
}
I feel like you are not getting the Data that you have stored in the AsyncStorage properly. Look at my two Functions for storing and retrieving the data by the key.
const storeData = async (key, value) => {
try {
await AsyncStorage.setItem(key, value);
} catch (error) {
console.log(error);
}
};
const getData = async (key) => {
try {
const data = await AsyncStorage.getItem(key);
if (data !== null) {
console.log(data);
return data;
}
} catch (error) {
console.log(error);
}
};
You can then call getData("yourKey") wherever you want to get the stored elements.
There are a couple of points here:
1- AsyncStorage.setItem() takes a key and a value that are both STRINGS. so you need to do await AsyncStorage.setItem('key', JSON.stringify(task)) in your storeData method
2- You need to READ the data once the component mounts and put it inside of your state using something like useEffect for it to be shown once you restart your app. For example:
useEffect(() => {
AsyncStorage.getItem('key').then((res) => {
setTask(JSON.parse(res));
})
} , [])
I have a component like this:
export const MyComp = () => {
const [showRules, setShowRules] = useState(false)
return (
<TouchableOpacity onPress={() => setShowRules(!showRules)} activeOpacity={1}>
<View>
<Inner expand={showRules}>
<Text>Content here </Text>
</Inner>
</View>
</TouchableOpacity>
)
}
I have another component where I expand/collapse stuff just like this. the logic is duplicated, just the state has different names. thought it could be a good use case for a custom hook
so I wrote this
export const useExpander = (setExpand) => {
const [show, setShow] = useState(false)
useEffect(() => {
if (setExpand) {
setShow(true)
} else {
setShow(false)
}
}, [])
return show
}
but I can't figure out how to use it?
I cant change this line: <TouchableOpacity onPress={() => useExpander(expand)} activeOpacity={1}>
as I think this violates hook rules
any ideas?
I'm trying to get a data firebase realtime database. I can show data with console.log() but I cannot show in Flat list. I tried different ways to solve this problem. But, I could not find any certain solution.
Here, my JSON tree in firebase:
Here, my code:
const NotesList = (props) => {
const { colors } = useTheme();
const styles = customStyles(colors);
const user = auth().currentUser
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const getData = () => {
firebase.database().ref(`notes/`).on('value', function (snapshot) {
console.log(snapshot.val())
});
}
useEffect(() => {
setTimeout(() => {
setData(getData);
setLoading(true);
}, 1000);
}, []);
const renderItem = ({ item }) => {
return (
<View style={{ marginRight: 10, marginLeft: 10 }}>
<TouchableOpacity>
<NoteCard title={item.noteTitle} icerik={item.noteDetails} date={item.timestamp} />
</TouchableOpacity>
</View>
);
};
const split = () => {
let icerik = data.map((item, key) => item.icerik);
return icerik.slice(0, 1) + '...';
};
return (
<View style={styles.container}>
<StatusBar barStyle="light-content" />
<NoteSearchBar />
{!loading ? (
<View style={{ alignItems: 'center' }}>
<ActivityIndicator color="#ff5227" />
</View>
) : (
<FlatList
data={data}
numColumns={2}
renderItem={renderItem}
keyExtractor={(item, index) => index.toString()}
/>
)}
<TouchableOpacity
style={styles.addButton}
onPress={() => props.navigation.navigate('AddNote')}>
<Plus width={40} height={40} fill="white" margin={10} />
</TouchableOpacity>
</View>
);
};
I tried many different ways, but no suggestions solved the problem. I would be glad if you could help.
Your getData doesn't return the data, as the data is loaded asynchronously. You should instead move he call to setData into your getData:
const getData = () => {
firebase.database().ref(`notes/`).on('value', function (snapshot) {
setData(snapshot.val());
});
}
useEffect(() => {
setTimeout(() => {
getData()
setLoading(true);
}, 1000);
}, []);
Now the call to setData will put the JSON into the state, which in turn forces React to repaint the UI with the new data.
Ciao, basically you made 2 mistake:
getData does not return nothing so data will be never updated with values from firebase;
useEffect has a strange implementation (it's useless call setTimeout you are already waiting data from firebase);
My suggestion is to call getData from useEffect like this:
useEffect(() => {
getData()
}, []);
And modify getData like this:
const getData = () => {
firebase.database().ref(`notes/`).on('value', function (snapshot) {
setData(snapshot.val());
setLoading(true);
});
}
I found solution and I want to share it with you guys.
I kept the data from firebase as a child at a new value, then I put it in setData. In this way, I can display the data in the flat list.
const getData = () => {
firebase.database().ref(`notes/`).on('value', snapshot => {
let responselist = Object.values(snapshot.val())
setData(responselist)
console.log(snapshot.val())
setLoading(true);
});
}
useEffect(() => {
getData();
}, []);
Also, while firebase realtime DB was working, a new method called Object method helped when taking child values in the JSON tree.
I am trying to pass values from one Functional Component to another Functional Component on navigation.navigate, on the first screen the value is there I can see it rendering it or on console.log, but when I try to get it on the second screen I get it "undefined".
Here I pass the value to the navigation.navigate:
<TouchableOpacity onPress = {() => navigation.navigate('AuditS',{audit:r.id})} style={styles.button}>
I will post my code bellow, if someone can give me a help I'll really appreciate it.
First Component:
import React, { createElement, useState, useEffect } from 'react';
import { Text, StyleSheet, View,TouchableOpacity,Image} from 'react-native';
import AuditButton from './component/AuditButton'
import axios from 'axios'
const HomeScreen = ({ navigation }) => {
const [checklists, setChecklists] = useState([]);
useEffect(() => {
axios.get("http://100.13.16.113:8081/api/checklists", {
}).then
(function (response) {
setChecklists(response.data);
console.log(response.data);
}).catch(error => {
console.log(error);
})
},[]);
return (
<View >
<Text style={styles.text}> Select an Audit</Text>
<View style={styles.maincontainer}>
<View style={styles.container}>
{checklists.map(r =>(
<TouchableOpacity onPress = {() => navigation.navigate('AuditS',{audit:r.id})} style={styles.button}>
<Image source={require('../assets/icons8-audit-80.png')}
style={styles.Image}>
</Image>
<Text style={styles.ButtonText}>{r.checklisT_DESCRIPTION}{r.id}</Text>
</TouchableOpacity >
))}
</View>
</View>
<View style={styles.bottomcontainer}>
<TouchableOpacity onPress = {() => navigation.navigate('Login')}
>
<Text style = {styles.logout}>LOGOUT</Text>
</TouchableOpacity>
</View>
</View>
);
};
Second Component:
import React, { createElement, useState,Component } from 'react';
import { Text, TextInput, StyleSheet,
View,TouchableOpacity,Image,ScrollView,Modal,TouchableHighlight} from 'react-native';
import {Collapse,CollapseHeader, CollapseBody} from 'accordion-collapse-react-native';
import AuditItem from './component/AuditItem'
import RNPickerSelect from 'react-native-picker-select';
import AuditCategory from './component/AuditCategory';
const AuditScreen = ({ audit, navigation}) =>
{
const [modalInfoVisible, setModalInfoVisible] = useState(false);
const [opNumber, setOP] = useState(false);
const [FGINumber, setFGI] = useState(false);
const [checklistitems, setChecklistitems] = useState([]);
const auditId = audit;
console.log(JSON.stringify(auditId));
return ()
I'd suggest you to use react-router-dom if you are working with router.
make some changes in second component like
const AuditScreen = () => //some changes in line
{
const {audit} = navigation.state.params; //added line
const [modalInfoVisible, setModalInfoVisible] = useState(false);
const [opNumber, setOP] = useState(false);
const [FGINumber, setFGI] = useState(false);
const [checklistitems, setChecklistitems] = useState([]);
const auditId = audit;
console.log(JSON.stringify(auditId));
return ()
Hope it helps!!!