Is there a way to set a state with textinput when onChangeText is already in use? - react-native

Im trying to set a state with the values from a textinput (which is a reusable component), Im using onChangeText to setFieldValue (useFormikContext()), I also want to set a state which will be sending to the Parent component. I tried using onChange but noticed it saves the text without the last word/number, for instance if I type 0123456789, the setFieldValue gets 0123456789, but the other one (with onChange) gets only 012345678 (without 9).
Here is the code:
function AppFormField({ name, width, childToParent, ...otherProps }) {
const { setFieldTouched, setFieldValue, errors, touched, values } =
useFormikContext();
return (
<>
<TextInput
onBlur={() => setFieldTouched(name)}
onChangeText={(text) => setFieldValue(name, text)}
onChange={() => childToParent(bn)}
value={values[name]}
width={width}
{...otherProps}
/>
<ErrorMessage error={errors[name]} visible={touched[name]} />
</>
);
}
Parent Component:
...
const [bn, setBN] = useState("");
const childToParent = (childdata) => {
setBN(childdata);
console.log(childdata);
};
console.log("bn");
console.log(bn);
...
return (
...
<UppFormField
keyboardType="numeric"
autoCorrect={false}
// icon="bank"
name="acct_number"
placeholder="Account Number"
style={{ paddingRight: 50 }}
childToParent={childToParent}
/>
...
)

Make a middle function called
const onTextChange = (text) => {
setFieldValue(text)
parentFunction(text)
}
then TextInput takes has
onChangeText={onTextChange}

Related

react-hook-form useFieldArray with React-Native

Is it possible to use ReactNative with useFieldArray from react-hook-form? I couldn't find any reference for that.
I'm trying to use it but I can't get the output data from the TextInputs. It looks like the onChange is not working, I tried to use the onChange prop but still couldn't make it.
Example:
const {
control,
formState: {errors},
register,
getValues,
handleSubmit,
} = useForm({
defaultValues: {
playerNameInput: [{playerName: ''}, {playerName: ''}],
},
});
const {fields, append, remove} = useFieldArray({
control,
name: 'playerNameInput',
});
return(
<>
{fields.map((player, index) => (
<View>
<Controller
control={control}
rules={{required: true}}
name="playerNameInput"
render={() => (
<TextInput
style={{width: 100}}
defaultValue={`${player.playerName}`}
{...register(`playerNameInput.${index}.playerName`)}
/>
)}
/>
</View>)}
<Button onPress={handleSubmit(data => console.log(data))}>
Save Changes
</Button>
</>
)

Strange behavior using useState to load data into a object state

i have broken my head trying to understand a problem with my code. I'm new with React Native so there may be a standard behavior that i am unaware of. This is my problem:
In my component i have a useEffect() to load my data like "componentDidMount":
useEffect( () => {
async function loadDadosLista(){
let listaRecebida = await getListaByID(route.params.idLista);
setLista(listaRecebida);
};
loadDadosLista();
}, []);
My function works correctly, the function getListaById accesses my realm.db and return my object lista. After that I can access the data and associate it with components of type TextInput. My real problem is that any change the i do in any component using properties of lista, overwrites all data leaving only the one that has been modified. I'm using spread operator but apparently it doesn't work. Below is my complete code for better understanding.
function ListConfig(){
const [lista, setLista] = useState({});
useEffect( () => {
async function loadDadosLista(){
let listaRecebida = await getListaByID(route.params.idLista);
setLista(listaRecebida);
};
loadDadosLista();
}, []);
return(
<View style={styles.container}>
<View style={[styles.containerLinha, styles.linha2]}>
<View style={styles.inputLocal}>
<TextInput
name='estabelecimento'
placeholder='Venda do seu Francisco'
placeholderTextColor={theme.colors.cinzaPrimario}
style={styles.textInputLocal(theme)}
value={lista.estabelecimento}
maxLength={25}
onChangeText={ (value) => {
setLista({
...lista,
estabelecimento: value
})
}}
textAlignVertical='bottom'
/>
<IconLocation width={20} height={24} />
</View>
</View>
<View style={styles.containerNotif}>
<Text style={styles.textoNotif(theme)}>
Me notifique 20 minutos antes
</Text>
<ToggleSwitch
isOn={lista.notificacaoAtiva}
onColor={theme.colors.cinzaSecundario}
offColor={theme.colors.cinzaSecundario}
thumbOnStyle={{
backgroundColor: theme.colors.destaque
}}
size="medium"
onToggle={(isOn) => {
setLista({
...lista,
notificacaoAtiva: isOn
});
}}
/>
</View>
</View>
);
}
export default ListConfig;
My object lista have this properties:
{
estabelecimento: 'nameOfEstabelecimento',
notificacaoAtiva: true
}

React-native FlatList component is Not Working

Hello I am a beginner to react-native. I was practicing with a basic app which reads the input from the user and display it in the screen. I am trying to use the FlatList but it is not rendering.
Here is my code
export default function App() {
const [enteredText, setEnteredText] = useState(
""
); /* constant and method with String*/
const [enteredString, setEnteredString] = useState(
[]
); /* constant and method with Array */
const enteredTextHandler = (enteredText) => {
setEnteredText(enteredText);
}; /* Set the entered text to the constant value*/
const addTextHandler = () => {
setEnteredString((currentString) => [
...currentString,
{ id: Math.random().toString(), value: enteredText },
]); /* Add entered text to the array */
};
return (
<View style={styles.mainView}>
<View style={styles.container}>
<TextInput
placeholder="Enter te value"
style={styles.input}
onChangeText={enteredTextHandler}
value={enteredText}
/>
<Button title="Add" onPress={addTextHandler} style={styles.button} />
</View>
<FlatList
data={enteredString}
keyExtractor={(item) => item.id}
renderItem={(itemData) => {
console.log(itemData.item.value);
<View style={styles.listStyle}>
<Text>{itemData.item.value}</Text>
</View>;
}}
/>
</View>
);
}
It might be because you've reused the variable name enteredText in your enteredTextHandler. I think the way it's set up it'll always set enteredText to blank.
Try using a different name for the text argument:
const enteredTextHandler = newText => {
setEnteredText(newText);
}; /* Set the entered text to the constant value*/
I got the answer
<FlatList
data={enteredString}
keyExtractor={(item, index) => item.id}
renderItem={(itemData) => (
<View style={styles.listStyle}>
<Text>{itemData.item.value}</Text>
</View>
)}
/>
I was written the syntax wrong. previously I used (itemData) => {} but the actual syntax is (itemData) => () . Instead of parantesis I used curly braces that's why it was not displaying.

How do I setState from toggle checkbox?

The setState is not working when I am trying to use the onToggle from the checkbox to set the state to true.
I have tried to console log the function and it works except that the state won't change.
import CircleCheckBox, { LABEL_POSITION } from 'react-native-circle-checkbox';
const MyTaskItem = (props) => {
return (
<CircleCheckBox
checked={props.taskDone}
onToggle={props.onToggleCheck}
/>
);
};
import MyTaskItem from "../../components/MyTaskItem";
export default function MyTasksScreen() {
const [taskDone, setTaskDone] = useState(false);
const checkDoneHandler = () => {
setTaskDone(true);
console.log(setTaskDone);
};
return (
<View style={styles.screen}>
<MyTaskInput visible={isAddMode} onAddTask={addTaskHandler} onCancel={cancelTaskAdditionHandler} />
<FlatList
keyExtractor={(item, index) => item.id}
data={myTasks}
renderItem={itemData =>
<MyTaskItem
id={itemData.item.id}
onDelete={removeTaskHandler}
title={itemData.item.title}
description={itemData.item.description}
onToggleCheck={checkDoneHandler}
/>}
/>
<AddTodoButton onPress={() => setIsAddMode(true)} />
</View>
);
}
I want to change the state on taskDone to true/false when toggling the checkbox.
I guess you want to change specific task state, so first of all, you need to pass the ID of the task which toggled, so MyTaskItem can be rewritten like this:
const MyTaskItem = (props) => {
const {taskDone, id, onToggleCheck} = props;
return (
<CircleCheckBox
checked={taskDone}
onToggle={()=>onToggleCheck(id)}
/>
);
};
Then you should handle items states in your MyTasksScreen.
Since FlatList is a PureComponent, therefore you need to pass the changing states to the extraData property of the flatlist, to inform item states has changed.
In case you want to change all items done state, you can do like this:
export default function MyTasksScreen() {
const [taskDone, setTaskDone] = useState(false);
const checkDoneHandler = () => {
setTaskDone(true);
console.log(setTaskDone);
};
return (
<View style={styles.screen}>
<MyTaskInput visible={isAddMode} onAddTask={addTaskHandler} onCancel={cancelTaskAdditionHandler} />
<FlatList
keyExtractor={(item, index) => item.id}
data={myTasks}
extraData={taskDone}
renderItem={itemData =>
<MyTaskItem
id={itemData.item.id}
onDelete={removeTaskHandler}
taskDone={taskDone}
title={itemData.item.title}
description={itemData.item.description}
onToggleCheck={checkDoneHandler}
/>}
/>
<AddTodoButton onPress={() => setIsAddMode(true)} />
</View>
);
}
I'd advise you to use TypeScript.
From the code you've added, looks like you're not sending taskDone to your MyTaskItem Component.
Also, try adding console.log(taskDone) after this line: const [taskDone, setTaskDone] = useState(false);

FlatList not rendering style dynamically

I'm currently struggling in making my FlatList applying the changes I do to it. What I am wanting right now is that when I click an item in my flatlist, that it highlights in a certain color. I followed an approach done by a guy but I am having the problem that to me is not working the update once I click.
I can see through console that all I am doing performs a modification but I think that I am missing some point with extraData parameter since it is not re-rendering with the backgroundColor that I would like to apply.
The code I have is as following, I know that the style I am applying is correct since if i substitute in the map styles.list per styles.selected, everything gets the background I would like to be applied to the elements I click.
So summarizing, the issue I think I have is that the flatlist is not re-rendering so it doesn't show the modifications I perform on it. Any idea of what I am doing wrong? Any tip?
render() {
const { students, studentsDataSource, loading, userProfile } = this.props.navigation.state.params.store;
this.state.dataSource = studentsDataSource._dataBlob.s1.map(item => {
item.isSelect = false;
item.selectedClass = styles.list;
return item;
})
const itemNumber = this.state.dataSource.filter(item => item.isSelect).length;
return (
<View style={styles.container}>
<Item rounded style={styles.searchBar}>
<Input placeholder='Group Name'/>
</Item>
<FlatList
style={{
flex: 1,
width: "100%",
}}
data={this.state.dataSource}
ItemSeparatorComponent={this.FlatListItemSeparator}
renderItem={ ({ item }) => (
<ListItem avatar style={[styles.list, item.selectedClass]}
onPress={() => this.selectItem(item)}>
<Left>
{!item.voteCount && <Avatar unseen={true} /> }
{!!item.voteCount > 0 && <Avatar />}
</Left>
<Body>
<Text>{item.name}</Text>
<Text note>{item.group}</Text>
</Body>
</ListItem>
)
}
listKey={item => item.key}
extraData={this.state}
/>
</View>
);
}
Here we can find the state and SelectItem functions:
constructor(props) {
super(props)
this.state = {
dataSource : [],
}
}
//FlatListItemSeparator = () => <View style={styles.line} />;
selectItem = data => {
//{console.log("inside SelectItem=", data)}
data.isSelect = !data.isSelect;
data.selectedClass = data.isSelect? styles.selected: styles.list;
const index = this.state.dataSource.findIndex( item => data.key === item.key);
this.state.dataSource[index] = data;
this.setState({
dataSource: this.state.dataSource,
});
console.log("This state has the changes:=",this.state.dataSource)
};
Well the main issue was that I was not using the .setState and instead I was doing assignations which killed the listeners.