I am trying to take a picture, and when that picture returns its prediction in the backend update the state. However, I cannot get the function to pass in, it only comes up as undefined. I know redux would probably be the best solution for this, but this is the only piece of state in the whole app where I have an issue, so I would rather avoid it if possible.
Here is my file:
const CameraRender = (props) => {
const [predictionLoaded, isPredictionLoaded] = useState(false);
const [showModal, changeModalVisability] = useState(false);
const [proportions, setProportions] = useState([]);
const { setCameraInactive } = props;
return(
<View style={styles.container}>
<Camera
style={styles.container}
ref={ref => {
this.camera = ref;
}}
>
<View style={styles.rectangle} />
<View style={styles.pictureButton}>
<Ionicons
name='ios-camera'
size={60}
color={'#cdd2c9'}
onPress={() => pictureHandler(this.camera, isPredictionLoaded(true),
changeModalVisability(true), ((p1, p2) =>
setProportions([p1, p2])))}
/>
</View>
</Camera>
{showModal &&
<PostPicModal
predictionLoaded
proportions
setCameraInactive={() => setCameraInactive()}
changeModalVisability={() => changeModalVisability(false)}
/>
}
</View>
);
}
const pictureHandler = async (camera, addPic, isPredictionLoaded,
changeModalVisability, setProportions) => {
const photo = await this.camera.takePictureAsync({ onPictureSaved: this.camera.pausePreview()});
changeModalVisability();
const prediction = await requestPrediction(photo.uri);
setProportions(prediction[0][0], prediction[0][1]); //THIS ISNT WORKING
isPredictionLoaded();
}
I know this is easy enough when I am passing it to another functional component, but I really just wanted to have a helper function that could take in the state. Should I just move picture handler right into the onPress? Thanks for the help.
Issue is with argument passing.
You are passing 4 arguments, however in your function you have expected 5 arguments.
I believe addPic is missing argument when you are calling a function.
I can see issue in passing arguments as well, it should be just isPredictionLoaded and inside the function you can call it with true or false like isPredictionLoaded(true)
Related
im trying to change the state using this but everyTime it takes add function only how to make the state change onPress ..what can i do please let me know
component //
<Searchitems
key={index}
crypto={crypto}
multipletest={multipletest}
remove={crypto => remove(crypto)}
add={crypto => add(crypto)}
// status={status}
removes="Remove"
adds="Add"
/>
const [statusss, setStatus] = React.useState(false);
onPress={() =>
setStatus(!statusss) ? props.remove(crypto) : props.add(crypto)
}
As mentioned in my comment, it is a bit difficult to understand what you are trying to do with your code. But still, try it like this. It appears that you are trying to check condition on a function.
const [statusss, setStatus] = React.useState(false);
useEffect(() => {
statusss ? props.remove(crypto) : props.add(crypto)
}, [statusss]);
<SomeComponent
onPress={() => setStatus(!statusss)}
/>
So I'm trying to do something very simple in my react native application, but it doesn't seem to be working correctly. I have a component in my native application that allows the user to create a post. The user can simply input the text that they would like as the body of their post. Of course I have decided to use the TextInput component for this and I am setting my body state by using onChangeText={text => onChangeText(text)}. When I click the create_post button in the upper right of the header I get "" as a value for the body.
I have other text input components throughout my application that work just as intended but for some reason this one is not. I have looked all over online and no one seems to have this issue. They only have an issue with it in a class component and not a functional component like the one I have here:
import React,{useLayoutEffect,useState} from 'react'
import { TextInput,ScrollView } from 'react-native'
import { Button } from './../components/Button';
const CreatePost = ({navigation,route}) => {
const [body,onChangeText] = useState('');
const [media,setMedia] = useState('');
useLayoutEffect(() => {
navigation.setOptions({
title: 'New Post',
headerRight: () => (
<Button style={{marginRight:40,fontSize:20}} title="Post" textColor="#0d00ff" onPress={create_post} />
)
})
},[])
const create_post = () => {
const timestamp = new Date().toISOString().split('.')[0];
console.log({body}); // expected: 'some text', result:""
const post = {
pid: 0,
username: 'head_honcho',
body: body
}
// makes call to database
navigation.navigate('HomeTab',{screen: 'Home',params:{post:post}});
}
return (
<ScrollView style={{padding:16}}>
<TextInput placeholder="What's happening?" keyboardType="default" value={body} style={{fontSize:20}} onChangeText={text => onChangeText(text)}/>
{/* <TouchableOpacity style={{justifyContent:'center',alignItems:'center', position:'absolute',bottom:0,left:0,right: 0}}>
<FontAwesome5 name="photo-video" size={20} />
<Text>Add Media</Text>
</TouchableOpacity> */}
</ScrollView>
)
}
export default CreatePost
I think this seems pretty straight forward and I feel silly having to ask a question so basic. My only other thought is that it has something to do with useLayoutEffect and that when create_post is called that it only has access to the initial state and not the updated one. If anyone has any ideas as to what I'm doing wrong that would be great. TIA!
EDIT
Just shortly after posting this I decided to see what would happen if I let useLayoutEffect check for updates in my body variable. Sure enough the body of the post actually came through as it should have.
useLayoutEffect(() => {
navigation.setOptions({
title: 'New Post',
headerRight: () => (
<Button style={{marginRight:40,fontSize:20}} title="Post" textColor="#0d00ff" onPress={create_post} />
)
})
},[body])
But I would still like to know why this is? Why doesn't onChangeText set my body variable as mentioned in the react documentation?
Also you can do it like this.
useLayoutEffect(() => {
navigation.setOptions({
title: 'New Post',
})
},[])
useEffect(() => {
navigation.setOptions({
headerRight: () => (
<Button style={{marginRight:40,fontSize:20}} title="Post" textColor="#0d00ff" onPress={create_post} />
)
},[body])
This way only the button is re rendered
function A() {
const [levels, setLevels] = React.useState(null);
// upon the component mount, we call the database.
React.useEffect(() => {
database()
.ref()
.once("value")
.then((snapshot) => {
//get Levels from db
const levels = snapshot.map((child) => child.key);
setLevels(levels);
});
}, []);
return (
<View>
{levels.map((element) => {
return <B level={element} />;
})}
</View>
);
}
function B(props){
const navigation = useNavigation();
return (
<View>
<TestButton
title={props.level}
onPress={() => navigation.navigate('C')}
/>
</View>
);
}
I currently am already passing the value 'level' to the TestFunc parameter, but now I wish to pass the same parameter to the screen I navigate to when I press the TestButton component.
https://reactnavigation.org/docs/params/
This documentation shows me how I would do such with a newly initialized parameter, but it doesn't seem to work with parameters that have been passed from previous screens.
Any suggestions?
EDIT:
I have tried to make it a little bit clearer. I want to go from function A to B to C, all different components/screens in my app. I want to take the 'level' that I obtain from function A and pass it from B to C. Currently I am correctly retrieving the 'level' value in function B, however I can not seem to pass it to function C.
function TestFunc (props){
const navigation = useNavigation();
return (
<View>
<TestButton
title={props.level}
onPress={() => navigation.navigate('Category',{...props})}
//{...props} send all props that's exist in props argument
/>
</View>
);
}
You can get the all props on Category component also
const { level } = this.props.navigation.state.params;
I'm trying out useFormContext in react to update a form by adding another section. Here's my code so far: https://codesandbox.io/s/funny-swanson-fiomq
I have the following:
season_form.js - the main form
season_data_form.js - the sub-form; originally, this was the only one being called by season_form.
challenge_form.js - this is the new section, also called by season_form.
My idea was to take out the form hooks from season_data_form.js and challenge_form.js, move it to season_form.js, and use useFormContext to transfer stuff in between, such as the registers, and submit actions.
However, I keep getting the following error, when run locally:
Cannot update a component (SeasonForm) while rendering a different
component (SeasonDataForm).
And then somewhere down the line, it says this:
Maximum update depth exceeded
I'm not sure which one to take first.
Near as I can tell, it happens in season_form.js, whenever the user tries to load the data in currentSeasonData by changing the value of seasonIndex:
const SeasonForm = () => {
const [seasonsData, setSeasonsData] = useState();
const [seasonIndex, setSeasonIndex] = useState(0);
const [currentSeasonData, setCurrentSeasonData] = useState(null);
const formMethods = useForm({ mode: "onBlur" });
const { register, errors, control, handleSubmit, reset, formState, setError } = formMethods;
const onSubmit = async (data) => { console.log(data); };
useEffect((_) => {
async function fetchData() {
try {
let data_seasons = await dbGetSeasons();
setSeasonsData(data_seasons);
if (data_seasons[0]) { setSeasonIndex(data_seasons[0].id); }
// ^^ Comment that out and the page will load, but will crash the moment you select anything in the dropdown.
} catch (error) {
console.error(error);
}
}
fetchData();
}, []);
useEffect((_) => {
seasonsData &&
seasonsData.forEach((data) => {
if (data.id === seasonIndex) { setCurrentSeasonData(data); }
});
},
[seasonIndex]
);
return (
<Box>
<Dropdown>
<Dropdown.Toggle variant="success" id="dropdown-basic">
{currentSeasonData ? (
<> {currentSeasonData.shortname} ({currentSeasonData.name}) </>
) : (
<>Choose a season...</>
)}
</Dropdown.Toggle>
{seasonsData && (
<Dropdown.Menu>
{seasonsData.map((season) => {
const seasonKey = "season-" + season.id;
return (
<Dropdown.Item key={seasonKey} onClick={() => { setSeasonIndex(season.id); }}>
{season.shortname} ({season.name})
</Dropdown.Item> );
})}
</Dropdown.Menu>
)}
</Dropdown>
<Accordion defaultActiveKey="toggle_season">
<FormProvider {...formMethods}>
<form onSubmit={handleSubmit(onSubmit)}>
<Card>
<Accordion.Toggle as={Card.Header} eventKey="toggle_season">
<Button variant="link">Season Data and Battle Pass</Button>
</Accordion.Toggle>
<Accordion.Collapse eventKey="toggle_season">
<Card.Body>
{currentSeasonData ? (<SeasonDataForm seasonData={currentSeasonData} />) : null}
</Card.Body>
</Accordion.Collapse>
</Card>
<Card>
<Accordion.Toggle as={Card.Header} eventKey="toggle_challenges">
<Button variant="link">Challenges</Button>
</Accordion.Toggle>
<Accordion.Collapse eventKey="toggle_challenges">
<Card.Body>
{currentSeasonData && currentSeasonData.pass_data && currentSeasonData.pass_data.challenges ? (
<ChallengeForm challenges={currentSeasonData.pass_data.challenges || {}} />
) : (
<Alert variant="danger">Missing `challenges` data</Alert>
)}
</Card.Body>
</Accordion.Collapse>
</Card>
</form>
</FormProvider>
</Accordion>
</Box> );
};
export default SeasonForm;
I really can't pinpoint what's happening. My limited experience with react tells me that some value somewhere, when changed, causes an infinite loop.
Of note is that commenting out <SeasonDataForm> allows the page to work, albeit with half the subforms gone.
Any ideas where I can fix this?
Can you try the following
const methods = useFormContext();
const register = methods.register();
const errors = methods.errors;
const control = methods.control;
const handleSubmit = methods.handleSubmit();
const reset = methods.reset;
const formState = methods.formState;
const setError = methods.setError();
const clearErrors = methods.clearErrors();
to
const methods = useFormContext();
const register = methods.register;
const errors = methods.errors;
const control = methods.control;
const handleSubmit = methods.handleSubmit;
const reset = methods.reset;
const formState = methods.formState;
const setError = methods.setError;
const clearErrors = methods.clearErrors;
It doesn't seem like the infinite loop is from your SeasonData, but because your are reassigning the functions to those variables, its not an issue to do so,
but the problem is that you are not just reassigning the functions to new variables, you are executing them by using "()", thats different you are getting the result of the function call not the function itself that way, so i removed the "()" from all except from "useFormContext()" where its mostly intentionally done ,
I hope this fix your issue
I am following the functional pattern as given by the expo project creation wizard, and I have a component like this:
Search.js
export default function Search() {
const [searchResults, setSearchResults] = React.useState(buildContentViews(contents));
return (
<View style={styles.container}>
<ScrollView contentContainerStyle={styles.contentContainer}>
<View style={styles.statusLine}>
<Text style={styles.statusLineText}>{(pageInfo.numResults || 0) + ' Treffer'}</Text>
</View>
{searchResults}
</ScrollView>
</View>
);
}
Now I have some non-react-native implementation for backend REST-services, which shall regularly update the search results. Therefore I would need to do something like:
export default function Search() {
const [searchResults, setSearchResults] = React.useState(buildContentViews(contents));
client.events.on('searchResults', (results) => setSearchResults(results));
return (
<View style={styles.container}>
<ScrollView contentContainerStyle={styles.contentContainer}>
<View style={styles.statusLine}>
<Text style={styles.statusLineText}>{(pageInfo.numResults || 0) + ' Treffer'}</Text>
</View>
{searchResults}
</ScrollView>
</View>
);
}
However I quickly get the error that too many event listeners are established, which is probably because the above code gets run every time the component is (re-)rendered, or in other words, whenver the component is updated.
So how would I correctly register the event listener and/or deregister the event listener in this scenario?
useEffect hook is your friend here!
This is how I handle registering/deregistering to a react-navigation event moving between the screens (I don't know how your client code works, this is just an example)
useEffect(() => {
const onFocus = () => {
// here I do something when the screen gets focused
}
// this is how you handle the registration to the event
const focusListener = navigation.addListener('didFocus', onFocus)
// and this is how to handle deregistration!
return () => focusListener.remove()
}, []) // empty array of dependencies
In the body of the useEffect hook, you define your actions;
the return function is used to clean-up effects, the perfect place to remove an event listener;
the empty array of dependencies assures you that this code will be executed just one time (after the first render) and no more! No more reallocation! The perfect way to define an event listener!