0

I'm facing a problem for a few days now and I might not be able to see the forest because of all the trees (I hope that German saying works in English as well ^^).

I'm building an app for cooking receipes to learn React Native. The app has an overview with the receipes, you can click on one and it forwards the id of that receipe to a detail screen. In that detail screen, I'm getting the data for that specific receipe the same way I do on the overview screen. But - while the overview screen works fine, the detail screen does not - the const [ receipes, setReceipes ] = useState({}) returns [object Object].

This is what I use on the overview screen to get my data:

  { /* functions to handle the receipe data stuff */ }
  const [ receipes, setReceipes ] = useState({});

  const [ presentTitle, setPresentTitle ] = useState('');
  const [ presentIngredients, setPresentIngredients ] = useState([]);
  const [ presentIngredient, setPresentIngredient ] = useState('');
  const [ presentHowTo, setPresentHowTo ] = useState('');
  const receipeKeys = Object.keys(receipes)

  { /* function to make a user write to their subdirectory in the database */ }
  const auth = getAuth()
  const userUID = auth.currentUser?.uid
  const databasePath = userUID+'/receipes'

  useEffect(() => {
    return onValue(ref(db, databasePath), querySnapshot => {
      let data = querySnapshot.val() || {};
      let receipeItems = {...data};
      setReceipes(receipeItems);

      console.log('ReceipeScreen | setReceipes = ', receipeItems)
    })
  }, [])

And how I forward it to the details screen:

{ /* main scroll view def */ }
  <ScrollView>
    {receipeKeys.length > 0 ? (
      receipeKeys.map(key => (

        // links to the matching detail screen, passing along the key of the receipe
        <TouchableOpacity
          key = {key}
          onPress={() => navigation.navigate('ReceipeDetailsScreen', key )} >
          <ReceipeItem
            key = {key}
            id = {key}
            receipe = {receipes[key]}
          />
          
        </TouchableOpacity>
      ))
    ) : (
      <Text>No receipes present.</Text>
    )}
  </ScrollView>

Here's the code I use on my detail screen to get my data (note the route props I'm using to then set my databasePath):

const ReceipeDetailScreen = ({ route }) => {

    const navigation = useNavigation();

    const [ receipes, setReceipes ] = useState({});

    { /* function to make a user write to their subdirectory in the database */ }
    const auth = getAuth()
    const userUID = auth.currentUser?.uid

    const currentReceipeID = route.params;
    const databasePath = userUID+'/receipes/'+currentReceipeID
    
    console.log("ReceipeDetailScreen.js | DatabasePath = " + databasePath)
    
    { /* working with the receipes data */}   
    useEffect(() => {
        return onValue(ref(db, databasePath), querySnapshot => {
            let data = querySnapshot.val() || {};
            let receipeData = {...data};
            setReceipes(receipeData);

            console.log('ReceipeDetailScreen.js | setReceipe = ', receipeData)
        })
    }, []) 

    console.log("ReceipeDetailScreen.js | receipe = " + receipes)

}

Unfortunately, this is what it looks when I'm printing it to the console: enter image description here

Any help on how to fix that would be much appreciated, thanks!

1
  • 1
    Try JSON.stringify(receipeData) so the object will be printed as a string. Commented Sep 9, 2022 at 10:37

2 Answers 2

2

I figured out a way how to do this, just in case someone has the same problem.

Instead of writing the data in useEffect to receipeData, I switched over to generating a list of the items keys in here. That way I can iterate over the list of keys and get the data for the matching key.

Let me show you what I mean:

Getting the data:

  const [ receipes, setReceipes ] = useState({});
  const [ presentIngredients, setPresentIngredients ] = useState({});
  const [ presentIngredient, setPresentIngredient ] = useState('');

  const ingredientsKeys = Object.keys(presentIngredients);

  { /* updates "receipes" and "presentIngredients", so we can get their keys 
  and use them to iterate over the objects */ }
  useEffect(() => {
    return onValue(ref(db, databasePath), querySnapshot => {
      let data = querySnapshot.val() || {};
      let receipeItems = {...data};
      setReceipes(receipeItems);
    }),

    onValue(ref( db, databasePathIngredients), querySnapshot => {
        let data = querySnapshot.val() || [];
        let ingresItems = {...data};
        setPresentIngredients(ingresItems);
    })
  }, [])

And then calling a custom item and forwarding the data:

 <View style={styles.ingredientsWrapper}>
      {ingredientsKeys.length > 0 ? (
      ingredientsKeys.map(key => (
        
        <Ingredients
            id={key}
            ingredients={presentIngredients[key]}
        />
        ))
      ) : (
        <Text style={styles.text}>Nothing there, please add something.</Text>
      )}
    </View>
Sign up to request clarification or add additional context in comments.

Comments

1

[object Object] is a way of displaying object in the console but this doesn't realy gives you information about the object itself.

You can try using JSON.stringify() to be able to see the content of your object in the console, you can use it this way : console.log('ReceipeDetailScreen.js | setReceipe = ', json.stringify(receipeData))

It might help you understand what's going on.


Edit due to new comment:

Considering that the object is empty I suppose that the method that you're using to get a single reciepe does not work properly, or maybe that your id is wrong?

A temporary fix could be to get the array and then filter it ot only get the reciepe that you want (not exactly clean code)

const ReceipeDetailScreen = ({ route }) => {

const navigation = useNavigation();

const [ receipes, setReceipes ] = useState({});

{ /* function to make a user write to their subdirectory in the database */ }
const auth = getAuth()
const userUID = auth.currentUser?.uid

const currentReceipeID = route.params;
const databasePath = userUID+'/receipes/';  // Remove id here

console.log("ReceipeDetailScreen.js | DatabasePath = " + databasePath)

{ /* working with the receipes data */}   
useEffect(() => {
    return onValue(ref(db, databasePath), querySnapshot => {
        let data = querySnapshot.val() || {};
        let receipeData = {...data};
        const receipe = receipeData.find(elt => elt.id === currentReceipeID ) // Search receipe here 
        if(receipe !== undefined){ 
           setReceipes(receipe); 
        }
        console.log('ReceipeDetailScreen.js | setReceipe = ', receipeData)
    })
}, []) 

console.log("ReceipeDetailScreen.js | receipe = " + receipes)

}

3 Comments

Thanks for your reply! Stringifying the console log removes the [object Object], but now it's just showing as an empty Object: LOG ReceipeDetailScreen.js | receipe = {} Running the same log on the overview screens returns this (and this is what I expect): ReceipeScreen.js | receipe = {"-NBWmacQJZYBKU-HHYFf":{"howTo":"Instructions go here.","ingredients":["Onions","Cheese"],"title":"Something tasty"}} But I still don't know why it won't work in the details screen, but does on the overview screen...
Just tried your suggested code (many thanks for that!), won't work. I then added a console print to the useEffect, right before the return function. Guess what, the statement was never printed, which let's me believe that useEffect is never called... (which is probably because it fails to render and never get's to the point were useEffect would be called, right?) Weirdly enough, adding the same statement to useEffect at the overview screen get's printed... Any idea what might cause that? Maybe the React Navigation has something do to with it...?
I don't understand, you could see this log console.log('ReceipeDetailScreen.js | setReceipe = ', receipeData) but not one placed on the first line of useEffect ? Can you post all the content of the file containing your ReceipeDetailScreen ? A screenshot of the device when you are entering the details screen could also help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.