简体   繁体   中英

react component not re-rendering after state change

It is rendering incorrectly when the page state changes I click on the category link and it checks if the link exists in category and then should set page state to category and likewise if I click on the recipe link it should set page state to recipe .

The value of isRecipe and isCategory are correct but it only sets the page state correctly after refreshing the page.

It should watch the page state and if this changes then it should re-render the component

How can I re-render the component if the page state changes?

const categories = [
 {name: 'first', slug: 'first'}, 
 {name: 'second', slug: 'second'},
]

const recipes = [
 {name: 'firstRecipe', slug: 'firstRecipe'},
 {name: 'secondRecipe', slug: 'secondRecipe'},
]

const Categories = ({ categories, recipe, recipes }) => {
  const router = useRouter()
  const { slug } = router.query

  const isRecipe = !!recipes.find(recipe => recipe.slug === slug)
  const isCategory = !!categories.find(cat => cat.slug === slug)

  const [page, setPage] = useState('')

  useEffect(() => {
    !!isCategory && setPage('category')
    !!isRecipe && setPage('recipe')
    }, [page])
  
  return (
    <>
      <a href="/first"> category </a>
      <a href="/firstRecipe"> recipe </a>
      {page === 'category' && <Category /> }
      {page === 'recipe' && <Recipes /> }
    </>
  )
}

export default Categories

Try this, with the additions to the dependencies:

const categories = [
 {name: 'first', slug: 'first'}, 
 {name: 'second', slug: 'second'},
]

const recipes = [
 {name: 'firstRecipe', slug: 'firstRecipe'},
 {name: 'secondRecipe', slug: 'secondRecipe'},
]

const Categories = ({ categories, recipe, recipes }) => {
  const router = useRouter()
  const { slug } = router.query

  const isRecipe = !!recipes.find(recipe => recipe.slug === slug)
  const isCategory = !!categories.find(cat => cat.slug === slug)

  const [page, setPage] = useState('')

  useEffect(() => {
    !!isCategory && setPage('category')
    !!isRecipe && setPage('recipe')
    }, [page, isRecipe, isCategory  ])
  
  return (
    <>
      <a href="/first"> category </a>
      <a href="/firstRecipe"> recipe </a>
      {page === 'category' && <Category /> }
      {page === 'recipe' && <Recipes /> }
    </>
  )
}

The dependencies of the useEffect hook are actually isRecipe and isCategory so instead of [page] , the effect should depend on [isRecipe, isCategory] .

Alternately, as the helpers ( isCategory and isRecipe ) are derived from the slug , they could be moved into the hook and then only [slug] would be required to set the proper hook dependencies.

Note: The setPage is not required to be given to the hook dependency list as it is guaranteed to be stable by React - omitting it is safe.

Ideally, the state could be avoided entirely by a simple computation like this:

page = null

if (isRecipe) {
  page = <Recipe />
} else if (isCategory) {
  page = <Category/>
}

...

<>
  ...
  {page}
<\>

There are actually three possible cases: recipe page, category page, and others that do not match the first two, which by rendering null will most likely result in what was anticipated by the code above.

Having less state, hooks, and mutations, results in less moving parts, thus most likely less bugs

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM