How can i input string data in object? - javascript

I'm trying to input text to innerState.feedType. but when i tried
it says Cannot read property 'toString' of undefined
How can i fix my code?
this is my code
const [innerState, setInnerState] = useState<any>({
feedType: 'bbong',
})
const onChangeEtcfeedtype = useCallback((text) => {
setInnerState( innerState['feedType'] = text)
},[]);
<TextInput
placeholder="input."
value={innerState.feedType}
onChangeText={onChangeEtcfeedtype}
/>

You need to add null-safety(?) operator, because state creates after render components. Also need to return new link on object for re-render component.
const [innerState, setInnerState] = useState<any>({
feedType: 'bbong',
})
const onChangeEtcfeedtype = (text) => {
setInnerState({...innerState, innerState.feedType: text});
};
<TextInput
placeholder="input."
value={innerState?.feedType}
onChangeText={onChangeEtcfeedtype}
/>

I think this is how you should write it.
About the error. It look like its not come from this part. It come from your <TextInput /> component and possiblely caused because what you doing with onChange event.
const [innerState, setInnerState] = useState<any>({
feedType: 'bbong',
})
const onChangeEtcfeedtype = useCallback((text) => {
setInnerState({feedType: text})
},[]);
<TextInput
placeholder="input."
value={innerState.feedType}
onChangeText={onChangeEtcfeedtype}
/>
Please do consider read these article:
https://xyproblem.info/
https://stackoverflow.com/help/how-to-ask

Here, innerState['feedType'] = text you are changing the state directly and then store it using the updater function, you should not change it directly.
You have innerState which is object and it contains feedType property. So, update a state you have to pass the object with the same key with new value.
Correct Way:
setInnerState({feedType: text})

Related

How do you update a react whose questions are generated from an object?

I'm trying to create a form in react, where I have the questions pulled from a flask backend as a dictionary, where in React it results in an object. As a result, I have the following code when the component is getting rendered:
const [questions, setQuestions] = useState('');
const [answers, setAnswers] = useState('');
/// answers are pulled from api, with questions and answers set up to be equal.
...
{ Object.entries(questions).map(([key, question]) =>
(
<>
<p> {question}</p>
<textarea value = {answers[key]} onChange = {(e) => setAnswers(prevAnswer => ({...prevAnswer, key:e.target.value}))}
type = 'text' required />
</>
)
)
}
I can update the value with the keys, but I don't know how to accept a value to the associated key in the object.
Edit ** I found a relevant post from a while back...
How do you rerender a React component when an object's property is updated?
I believe this bit:
<textarea
value={answers[key]}
onChange={
(e) =>
setAnswers(prevAnswer => ({
...prevAnswer,
key: e.target.value
}))
}
type='text'
required
/>
is just going to set the literal key "key" to the new value. Instead we want to do this:
<textarea
value={answers[key]}
onChange={
(e) =>
setAnswers(prevAnswer => ({
...prevAnswer,
[key]: e.target.value // <-- note `[key]:` here rather than `key:`
}))
}
type='text'
required
/>

Select specific checkbox among an array of checkboxes

I have data coming from getTasks() and I store it on tasks
I created a component for each task with their data with a checkbox for each task.
I want to click a checkbox and display only the one I clicked, not them all.
I am using React Native. How can I do this?
thanks.
export default () => {
const [tasks, setTasks] = React.useState([]);
const [checked, setChecked] = React.useState(false);
React.useEffect(() => {
(async () => {
const response = await getTasks();
setTasks(response);
})();
}, []);
return tasks.map(({id, title, description, date}) => (
<View key={id} style={styles.task}>
<CheckBox
value={checked}
onValueChange={() => {
setChecked((prevState) => !prevState);
}}
/>
<View style={styles.taskTextContainer}>
<Text>{title}</Text>
<Text>{description}</Text>
<Text>{date}</Text>
</View>
</View>
));
};
You're passing the same value={checked} to all checkboxes. You can create an array of booleans to accomplish that.
You have two problems in that code, first is the problem you described, the second one is the way you're changing the state of that checkbox.
About the first problem, in order to display the respective state for each task, you should also include a property that defines if the task is marked or not.
First, verify the name of the property thats set if the task is done or not, I'll give the name here as done and done is of type boolean.
// notice the done property
return tasks.map(({id, title, description, date, done}) => (
Then, you should use done to change the checked state of your Checkbox like this:
<Checkbox
value={done}
...
/>
Now you should change a little how you change that checked state.
First, you need to write a function to change the value of done, to fase or true, according by the Checkbox component's state and that's really simple:
const onCheckboxChange = (taskId) => {
// first, let's find the index of the changed task
const index = tasks.findIndex(({ id }) => id === taskId)
// next, let's get the data by the index
const data = tasks[index]
// now, we can just toggle done value like this
data.done = !data.done
// then, let's assign updated data to its own index in tasks array
tasks[index] = data
// finally, we can update the tasks state using a copy of changed tasks
setTasks([...tasks])
}

Working with react input field says synthetic even when i try and save, and setting value instead of defaultValue is rendering [Object, object]

Disclaimer I am new to developing. I am having trouble when I try and save my changes on my input field I get an error saying
"Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property nativeEvent on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist()."
Also if I set the "value" instead of the "defaultValue" when I type in the field I get [Object, object].
This is the input component:
const Profile = ({
profile,
mCatalog,
sCatalog,
isEditing,
onChange,
restoreData,
userID,
}) => {
const updateProviderNotes = (event) => {
const { name, value } = event.target;
onChange(name)(value);
}
return (
<Input
type="textarea"
disbaled={false}
name="providerNotes"
value={providerNote}
onChange={updateProviderNotes}
/>
)
const Editor = ({ source, onChange, items, oldItems, name }) => {
return (
<div className="d-flex ml-3">
<div className={styles.bubble}>
<ListEditor
items={items}
oldItems={oldItems || []}
itemListSource={source}
onChange={onChange(name)}
/>
</div>
</div>
);
};
export default Profile;
this is a portion of the parent component
const ProfileData = ({
profile,
mCatalog,
sCatalog,
page,
catalog,
userID,
setProfile,
}) => {
const [editingProfile, setEditingProfile] = useState(false);
const [oldProfile, setOldProfile] = useState(false);
useEffect(() => {
setOldProfile(profile)
}, [])
const handleMProfileCancel = () => {
setProfile(oldProfile)
}
const handleMedicalProfileSave = () => {
console.log("profile", profile)
console.log(typeof profile.medicalProfile.providerNotes)
api.UserRecords.updateMedicalProfile(userID, profile.medicalProfile)
setOldProfile(profile)
}
const updateMedicalProfileDetails = (fieldName) => (value) => {
setProfile({ ...profile, mProfile: {...profile.mProfile, [fieldName]: value }});
};
return (
{page === "medicalProfile" && (
<InfoEditWrapper
data={oldProfile.medicalProfile}
onCancel={handleMedicalProfileCancel}
onSave={handleMedicalProfileSave}
>
<Profile
profile={profile.medicalProfile}
medicalCatalog={medicalCatalog}
surgicalCatalog={surgicalCatalog}
onChange={updateMedicalProfileDetails}
userID={userID}
/>
</InfoEditWrapper>
)}
)
export default ProfileData;
Any advice would be helpful thanks!
For your warning message, I would refer to this question. You are basically getting this error because you are using your event in an asynchronous context (updating your state) which isn't allowed. You can avoid this error if you assign your event to a local variable and reference it.
if I set the "value" instead of the "defaultValue" when I type in the
field I get [Object, object]
Your onChange event handler will receive a Synthetic event object and your parameter you're passing with it. With your current code you assigned the whole event object as the field value.
Your updateMedicialProfileDetails method that you are passing as the onChange prop isn't in your question so I'm using the updateProfileDetails method as an example:
The following code should work:
const updateProfileDetails = (fieldName) => (event) => {
const { value } = event.target;
setProfile({ ...profile, mProfile: {...profile.mProfile, [fieldName]: value }});
};
Your name parameter you are passing with this function is unnecessary since your event object will have the name attribute available, so your code can be updated to the following:
<Input
type="textarea"
name="providerNotes"
value={profile.providerNotes}
onChange={onChange}
oldValue={restoreData.providerNotes}
/>
The event handler:
const updateProfileDetails = (event) => {
const { name, value } = event.target;
setProfile({ ...profile, mProfile: {...profile.mProfile, [name]: value }});
};

React Native load data from API using hooks

Im new in ReactNative and I'm trying to take some data from here https://www.dystans.org/route.json?stops=Hamburg|Berlin
When I try console.log results it return full API response. I dont know why in first results.distance works and return distance, but when I'm trying to do it inside FlatList nothing is returned. Sometimes it works when i want to return only item.distance but can't somethnig like <Text>{item.stops[0].nearByCities[0].city}</Text> nowhere in my code also in console. Im getting error:
undefined is not an object (evaluating 'results.stops[0]')
imports...
const NewOrContinueScreen = ({ navigation }) => {
const [searchApi, results, errorMessage] = useDystans();
console.log(results.distance);
return (
<SafeAreaView forceInset={{ top: "always" }}>
<Text h3 style={styles.text}>
Distance: {results.distance}
</Text>
<Spacer />
<FlatList
extraData={true}
data={results}
renderItem={({ item }) => (
<Text>{item.distance}</Text>
// <Text>{item.stops[0].nearByCities[0].city}</Text>
)}
keyExtractor={item => item.distance}
/>
<Spacer />
</SafeAreaView>
);
};
const styles = StyleSheet.create({});
export default NewOrContinueScreen;
And here is my hook code:
import { useEffect, useState } from "react";
import dystans from "../api/dystans";
export default () => {
const [results, setResults] = useState([]);
const [errorMessage, setErrorMessage] = useState("");
const searchApi = async () => {
try {
const response = await dystans.get("route.json?stops=Hamburg|Berlin", {});
setResults(response.data);
} catch (err) {
setErrorMessage("Something went wrong with useDystans");
}
};
useEffect(() => {
searchApi();
}, []);
return [searchApi, results, errorMessage];
};
As the name implies, FlatList is designed to render a list. Your API endpoint returns a JSON Object, not an Array, so there's nothing for the FlatList to iterate. If you want to show all the stops in the list, try passing in the stops list directly.
<FlatList
data={results.stops}
renderItem={({ item }) => (<Text>{item.nearByCities[0].city}</Text>)}
/>
Some side notes: (1) The extraData parameter is used to indicate if the list should re-render when a variable other than data changes. I don't think you need it here at all, but even if you did, passing in true wouldn't have any effect, you need to pass it the name(s) of the variable(s). (2) The keyExtractor parameter is used to key the rendered items from a field inside of them. The stop objects from the API don't have a member called distance so what you had there won't work. From my quick look at the API response, I didn't see any unique IDs for the stops, so you're probably better off letting React key them from the index automatically.

Updating object with useState Hook after rendering text input

I'm in the early process of building a commissioning checklist application for our company. Since the checklist is fairly large (and many of them) I wanted to create a function that maps through an object and after rendering the values written would update the appropriate states with a useState Hook.
The page is rendering without any issues. The problem only appears once the input is changed. Instead of updating the correct state in the object. It seems the logic is adding an additional section in my object and creating another input element.
import React, { useState } from 'react'
const ProjectInfo = () => {
const _renderObject= () => {
return Object.keys(answers).map((obj, i) => {
return(
<div key={obj}>
<label>{answers[obj].question}</label>
<input type="text" onChange={(e, obj) => setAnswer(
{
...answers,
obj:{
value: e.target.value
}})} />
</div>
)
})
}
const [answers, setAnswer] = useState({
11:{
question:"Project Name",
value:""
},
12:{
question:"Project Number",
value:""
}
})
return(
<div>
<section>
{_renderObject()}
</section>
<p>{`Project Number is: ${answers[11].value}`}</p>
<p>{`Project Name is: ${answers[12].value}`}</p>
</div>
)
}
export default ProjectInfo
I was expecting for the state to just update as normal. But what I'm suspecting is in my renderObject method my obj variable for my .map function is not being used inside my setAnswer function and causes another field to be created with a key name of "obj".
If this is the issue is it possible to have the setAnswer function in my renderObject Method to use the "obj" value of the map function and not the actual value of the word obj as key?
If not what would be the best way to approach this? I was thinking of adding a submit button at the bottom of the screen and updating all states with an onClick event listener. But now I'm think I'll have the same issue since the scope of the obj variable isn't resolved.
Any help would be greatly appreciated. I've only been doing this for a couple of months, any advice and feedback would also be appreciated!
You seem to be not using the dynamic key correctly while updating state. Also you need to update the value within the key and not override it. Also obj shouldn't be the second argument to onChange instead it must be received from the enclosing scope
const _renderObject= () => {
return Object.keys(answers).map((obj, i) => {
return(
<div key={obj}>
<label>{answers[obj].question}</label>
<input type="text" onChange={(e) => setAnswer(
{
...answers,
[obj]:{
...answers[obj],
value: e.target.value
}})} />
</div>
)
})
onChange={(e, obj) => setAnswer(
{
...answers,
obj:{
value: e.target.value
}})}
Here you spreading answers and add another object with the target value. that is the issue. Hope you understand the point.
TRY THIS
onChange={
(e, obj) => {
const updatedAnswer = answer.map(ans => ans.question === obj.question ? {...ans,value: e.target.value }:ans)
setAnswer(
{
...updatedAnswer
}
)
}
}
BW your object should contain propper ID for the key.
Its because you are not updating the keys correctly and you need to pass obj in input onchange callback as it make another reference, not the mapped array(obj). So in your case that obj is undefined. Here is working code :
const _renderObject = () => {
return Object.keys(answers).map((obj, i) => {
return (
<div key={obj}>
<label>{answers[obj].question}</label>
<input
type="text"
onChange={e =>
setAnswer({
...answers,
[obj]: { //take obj
...answers[obj],//keep specific object question
value: e.target.value//change only specfic object value
}
})
}
/>
</div>
);
});
};
Here is working url: https://codesandbox.io/s/hardcore-pike-s2hfx

Categories