Home > Net >  Function in react.js needs to run twice to work
Function in react.js needs to run twice to work

Time:07-13

I am doing a React project with Firestore. Using API results, I want users to be able to same some as favorites. This is doable, but when you clicked first, handleFavorite() and saveFavorite() return an empty string for every field. The second time, all values are correct.

export default function MostPopular() {
  const [mostPopulars, setMostPopulars] = useState([])
  const { currentUser } = useAuth()

  const [author, setAuthor] = useState('')
  const [date, setDate] = useState('')
  const [description, setDescription] = useState('')
  const [section, setSection] = useState('')

  const [title, setTitle] = useState('')
  const [url, setUrl] = useState('')
  const [user, setUser] = useState('')

  /* firestore collection */
  const favoritesCollectionRef = collection(db, 'favorites')
  /* console.log(favoritesCollectionRef) */
  function handleFavorite(post) {
    setUser(currentUser.uid)
    setAuthor(post.byline)
    setDate(post.published_date)
    setDescription(post.abstract)
    setSection(post.section)
    setTitle(post.title)
    setUrl(post.url)

    setUser(currentUser.uid)
    console.log({ author, date, description, section, title, url, user })
  }

  const saveFavorite = async (post) => {
    setAuthor(post.byline)
    setDate(post.published_date)
    setDescription(post.abstract)
    setSection(post.section)
    setTitle(post.title)
    setUrl(post.url)

    setUser(currentUser.uid)

    try {
      await addDoc(favoritesCollectionRef, {
        author,
        date,
        description,
        section,
        title,
        url,
        user,
      })
      console.log('favorite added')
    } catch (err) {
      console.log(err)
    }
  }

  useEffect(() => {
    /* most popular */
    axios
      .get(nytMostPopularUrl)
      .then((response) => {
        /* console.log(response.data.results) */
        setMostPopulars(response.data.results)
      })
      .catch((err) => {
        console.log(err)
        setMostPopulars(data)
      })
  }, [])

  return (
    <div className='most-populars'>
      {mostPopulars.map((post, index) => (
        <Card
          className='most-populars__card  card bg-dark text-light border-light'
          key={index}
        >
          <span onClick={() => handleFavorite(post)}>handleFavorite here</span>
          <span onClick={() => saveFavorite(post)}>save favorite here</span>
          <Card.Body>
            {' '}
            <div className='title-card'>{post.title}</div>
            <div className='subtitle'>{post.abstract}</div>
            <Card.Text className='author-date'>
              <span>{post.byline}</span>{' '}
              <span>
                Published: {moment(post.published_date).format('MMMM d, YYYY')}
              </span>
            </Card.Text>
            <Button className='btn read-more' variant='btn btn-outline-light'>
              <a href={post.url} className='link'>
                read more
              </a>
            </Button>
          </Card.Body>

          <Card.Footer>
            <SharingButtons url={post.url} />
          </Card.Footer>
        </Card>
      ))}
    </div>
  )
}

Async problems, maybe? Everything else works fine.

CodePudding user response:

Everything is fine with your code, problem is just that you can not expect to access new state immediately after state update, because you are accessing state from closure which recreates only after element rerenders. If you want to check state using console.log, you will need to move console.log outside of the handler function, in component body, and like that you will get logs on each rerender.

For example:

  function handleFavorite(post) {
    setUser(currentUser.uid)
    setAuthor(post.byline)
    setDate(post.published_date)
    setDescription(post.abstract)
    setSection(post.section)
    setTitle(post.title)
    setUrl(post.url)

    setUser(currentUser.uid)
  }

   console.log({ author, date, description, section, title, url, user }); // MOVE HERE

  const saveFavorite = async (post) => {
    setAuthor(post.byline)
    setDate(post.published_date)
    setDescription(post.abstract)
    setSection(post.section)
    setTitle(post.title)
    setUrl(post.url)

    setUser(currentUser.uid)

    try {
      await addDoc(favoritesCollectionRef, {
        author,
        date,
        description,
        section,
        title,
        url,
        user,
      })
      console.log('favorite added')
    } catch (err) {
      console.log(err)
    }

}

CodePudding user response:

Problem fixed. Used a class component instead for each. Initial state is each value I need. So far this work. Closing this issue.

  • Related