Render component when changes value in ReactJS.

huangapple go评论76阅读模式
英文:

ReactJS how to render component when changes value

问题

以下是您要翻译的代码部分:

Header Page:

import React, { useContext, useState, useEffect } from 'react';
import { Container, Navbar, Nav } from 'react-bootstrap';
import { ThemeContext } from '../GlobalComponents/ThemeProvider';
import { BiSun, BiMoon, BiCart } from 'react-icons/bi';
import { VscAccount } from 'react-icons/vsc';
import { Link } from "@reach/router";
import { useCart } from "react-use-cart";
import { useAuth0 } from "@auth0/auth0-react";

const Header = () => {
  const { theme, setThemeMode } = useContext(ThemeContext);
  const [darkMode, setDarkMode] = useState(theme);
  const { loginWithRedirect, logout, isAuthenticated, user, isLoading } = useAuth0();

  const [count, setCount] = useState((JSON.parse(localStorage.getItem("liked"))));

  const cou = () => {
    let oldData = JSON.parse(localStorage.getItem('liked') || "[]")
    if (oldData.length === count.length) {
      setCount((JSON.parse(localStorage.getItem("liked"))))
    } else {
      setCount((JSON.parse(localStorage.getItem("liked"))))
    }
  };

  useEffect(() => {
    let oldData = JSON.parse(localStorage.getItem('liked') || "[]")
    if (oldData.length === count.length) {
      setCount((JSON.parse(localStorage.getItem("liked"))))
    } else {
      setCount((JSON.parse(localStorage.getItem("liked"))))
    }
  }, [count]);

  useEffect(() => {
    setThemeMode(darkMode);
    console.log(darkMode)
  }, [darkMode]);

  const {
    isEmpty,
    totalItems,
  } = useCart();

  if (isLoading) {
    return (
      <Navbar collapseOnSelect expand="md"
        variant={darkMode ? 'dark' : 'light'}
        className={darkMode ? 'bg-light-black border-bottom' : 'bg-light border-bottom'}
        style={{ width: '100%', position: 'fixed', zIndex: 100 }}
      >
        <Container>
          <Link to="/">
            <Navbar.Brand className={darkMode ? 'text-dark-primary' : 'text-light-primary'}>
              <img src='https://i.ibb.co/7kZrn4H/33342.png' width={200} />
            </Navbar.Brand>
          </Link>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Nav className="ms-auto">
              <div className='load'><div class="lds-ellipsis"><div></div><div></div><div></div><div></div></div></div>
              <Nav.Link
                className={darkMode ? 'text-dark-primary' : 'text-light-primary'}
                onClick={() => setDarkMode(!darkMode)}
              >
                {darkMode ? <BiSun size="1.7rem" /> : <BiMoon size="1.7rem" />}
              </Nav.Link>
              <Link
                to="/cart"
                className={`${darkMode ? 'text-dark-primary' : 'text-light-primary'} d-flex align-items-center`}
              >
                <BiCart size="2rem" />
                {!isEmpty && <span style={{ position: 'relative', left: '-21px', top: '-18px' }}>{totalItems}</span>}
                <span style={{ marginLeft: !isEmpty ? '-13px' : 0 }}>&nbsp;Cart</span>
              </Link>
              <Link
                to="/wishlist"
                className={`${darkMode ? 'text-dark-primary' : 'text-light-primary'} d-flex align-items-center`}
              >
                <BiCart size="2rem" />
                {!isEmpty && <span style={{ position: 'relative', left: '-21px', top: '-18px' }}>{count.length}</span>}
                <span style={{ marginLeft: !isEmpty ? '-13px' : 0 }}>&nbsp;Wishlist</span>
              </Link>
              {
                isAuthenticated ? (
                  <>

                    <button onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })} className={`login-btn ${darkMode ? 'text-dark-primary' : 'text-light-primary'}`}>
                      Log Out
                    </button>
                  </>
                ) : (
                  <>

                    <button onClick={() => loginWithRedirect()} className={`login-btn ${darkMode ? 'text-dark-primary' : 'text-light-primary'}`}>
                      Log in
                    </button>
                  </>
                )
              }
            </Nav>
          </Navbar.Collapse>
        </Container>
      </Navbar>
    );
  };

  return (
    <Navbar collapseOnSelect expand="md"
      variant={darkMode ? 'dark' : 'light'}
      className={darkMode ? 'bg-light-black border-bottom' : 'bg-light border-bottom'}
      style={{ width: '100%', position: 'fixed', zIndex: 100 }}
    >
      <Container>
        <Link to="/">
          <Navbar.Brand className={darkMode ? 'text-dark-primary' : 'text-light-primary'}>
            <img src='https://i.ibb.co/7kZrn4H/33342.png' width={200} />
          </Navbar.Brand>
        </Link>
        <Navbar.Toggle aria-controls="basic-navbar-nav" />
        <Navbar.Collapse id="basic-navbar-nav">
          <Nav className="ms-auto">
            {
              isAuthenticated && (
                <>
                  <p className={`d-flex align-items-center user-name ${darkMode ? 'text-dark-primary' : 'text-light-primary'}`}>{user.email}</p>
                </>
              )
            }
            <Nav.Link
              className={darkMode ? 'text-dark-primary' : 'text-light-primary'}
              onClick={() => setDarkMode(!darkMode)}
            >
              {darkMode ? <BiSun size="1.7rem" /> : <BiMoon size="1.7rem" />}
            </Nav.Link>
            <Link
              to="/cart"
              className={`${darkMode ? 'text-dark-primary' : 'text-light-primary'} d-flex align-items-center`}
            >
              <BiCart size="2rem" />
              {!isEmpty && <span style={{ position: 'relative', left: '-21px', top: '-18px' }}>{totalItems}</span>}
              <span style={{ marginLeft: !isEmpty ? '-13px' : 0 }}>&nbsp;Cart</span>
            </Link>
            <Link
              to="/wishlist"
              className={`${darkMode ? 'text-dark-primary' : 'text-light-primary'} d-flex align-items-center`}
            >
              <BiCart size="2rem" />
              {!isEmpty && <span style={{ position: 'relative', left: '-21px', top: '-18px' }}>{count.length}</span>}
              <span style={{ marginLeft: !isEmpty ? '-13px' : 0 }}>&nbsp;Wishlist</span>
            </Link>
            {
              isAuthenticated ? (
                <>

                  <button onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })} className={`login-btn ${darkMode ? 'text-dark-primary' : 'text-light-primary'}`}>
                    Log Out
                  </button>
                </>
              ) : (
                <

<details>
<summary>英文:</summary>

i have wishlist. When i adding items to my wishlist, i am adding items to my localStorage. And i need to show how many items i added to my wishlist. 
i dont know how to render header (automatically) when changes value in (localStorage).

When i add items to wishlist it shows in span tag, everything good but in console i am getting: Warning: Maximum update depth exceeded.
 
Can someone help please?
Everything is on header component(page)
Header Page:

import React, { useContext, useState, useEffect } from 'react';
import { Container, Navbar, Nav } from 'react-bootstrap';
import { ThemeContext } from '../GlobalComponents/ThemeProvider';
import { BiSun, BiMoon, BiCart } from 'react-icons/bi';
import { VscAccount } from 'react-icons/vsc';
import { Link } from "@reach/router";
import { useCart } from "react-use-cart";
import { useAuth0 } from "@auth0/auth0-react";

const Header = () => {
const { theme, setThemeMode } = useContext(ThemeContext);
const [darkMode, setDarkMode] = useState(theme);
const { loginWithRedirect, logout, isAuthenticated, user, isLoading } = useAuth0();

const [count, setCount] = useState((JSON.parse(localStorage.getItem("liked"))));

const cou = () => {
let oldData = JSON.parse(localStorage.getItem('liked') || "[]")
if (oldData.length === count.length) {
setCount((JSON.parse(localStorage.getItem("liked"))))
} else {
setCount((JSON.parse(localStorage.getItem("liked"))))
}
};

useEffect(() => {
let oldData = JSON.parse(localStorage.getItem('liked') || "[]")
if (oldData.length === count.length) {
setCount((JSON.parse(localStorage.getItem("liked"))))
} else {
setCount((JSON.parse(localStorage.getItem("liked"))))
}
}, [count]);

useEffect(() => {
setThemeMode(darkMode);
console.log(darkMode)
}, [darkMode]);

const {
isEmpty,
totalItems,
} = useCart();

if (isLoading) {
return (
<Navbar collapseOnSelect expand="md"
variant={darkMode ? 'dark' : 'light'}
className={darkMode ? 'bg-light-black border-bottom' : 'bg-light border-bottom'}
style={{ width: '100%', position: 'fixed', zIndex: 100 }}
>
<Container>
<Link to="/">
<Navbar.Brand className={darkMode ? 'text-dark-primary' : 'text-light-primary'}>
<img src='https://i.ibb.co/7kZrn4H/33342.png' width={200} />

        &lt;/Navbar.Brand&gt;
&lt;/Link&gt;
&lt;Navbar.Toggle aria-controls=&quot;basic-navbar-nav&quot; /&gt;
&lt;Navbar.Collapse id=&quot;basic-navbar-nav&quot;&gt;
&lt;Nav className=&quot;ms-auto&quot;&gt;
&lt;div className=&#39;load&#39;&gt;&lt;div class=&quot;lds-ellipsis&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;Nav.Link
className={darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;}
onClick={() =&gt; setDarkMode(!darkMode)}
&gt;
{darkMode ? &lt;BiSun size=&quot;1.7rem&quot; /&gt; : &lt;BiMoon size=&quot;1.7rem&quot; /&gt;}
&lt;/Nav.Link&gt;
&lt;Link
to=&quot;/cart&quot;
className={`${darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;} d-flex align-items-center`}
&gt;
&lt;BiCart size=&quot;2rem&quot; /&gt;
{!isEmpty &amp;&amp; &lt;span style={{ position: &#39;relative&#39;, left: &#39;-21px&#39;, top: &#39;-18px&#39; }}&gt;{totalItems}&lt;/span&gt;}
&lt;span style={{ marginLeft: !isEmpty ? &#39;-13px&#39; : 0 }}&gt;&amp;nbsp;Cart&lt;/span&gt;
&lt;/Link&gt;
&lt;Link
to=&quot;/wishlist&quot;
className={`${darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;} d-flex align-items-center`}
&gt;
&lt;BiCart size=&quot;2rem&quot; /&gt;
{!isEmpty &amp;&amp; &lt;span style={{ position: &#39;relative&#39;, left: &#39;-21px&#39;, top: &#39;-18px&#39; }}&gt;&lt;/span&gt;}
&lt;span style={{ marginLeft: !isEmpty ? &#39;-13px&#39; : 0 }}&gt;&amp;nbsp;Wishlist&lt;/span&gt;
&lt;/Link&gt;
{
isAuthenticated ? (
&lt;&gt;
&lt;button onClick={() =&gt; logout({ logoutParams: { returnTo: window.location.origin } })} className={`login-btn ${darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;}`}&gt;
Log Out
&lt;/button&gt;
&lt;/&gt;
) : (
&lt;&gt;
&lt;button onClick={() =&gt; loginWithRedirect()} className={`login-btn ${darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;}`}&gt;
Log in
&lt;/button&gt;
&lt;/&gt;
)
}
&lt;/Nav&gt;
&lt;/Navbar.Collapse&gt;
&lt;/Container&gt;
&lt;/Navbar&gt;
);

};

return (
<Navbar collapseOnSelect expand="md"
variant={darkMode ? 'dark' : 'light'}
className={darkMode ? 'bg-light-black border-bottom' : 'bg-light border-bottom'}
style={{ width: '100%', position: 'fixed', zIndex: 100 }}
>
{/* <button onClick={()=>cou()}>Ref</button> */}
<Container>
<Link to="/">
<Navbar.Brand className={darkMode ? 'text-dark-primary' : 'text-light-primary'}>
<img src='https://i.ibb.co/7kZrn4H/33342.png' width={200} />

      &lt;/Navbar.Brand&gt;
&lt;/Link&gt;
&lt;Navbar.Toggle aria-controls=&quot;basic-navbar-nav&quot; /&gt;
&lt;Navbar.Collapse id=&quot;basic-navbar-nav&quot;&gt;
&lt;Nav className=&quot;ms-auto&quot;&gt;
{
isAuthenticated &amp;&amp; (
&lt;&gt;
&lt;p className={`d-flex align-items-center user-name ${darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;}`}&gt;{user.email}&lt;/p&gt;
&lt;/&gt;
)
}
&lt;Nav.Link
className={darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;}
onClick={() =&gt; setDarkMode(!darkMode)}
&gt;
{darkMode ? &lt;BiSun size=&quot;1.7rem&quot; /&gt; : &lt;BiMoon size=&quot;1.7rem&quot; /&gt;}
&lt;/Nav.Link&gt;
&lt;Link
to=&quot;/cart&quot;
className={`${darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;} d-flex align-items-center`}
&gt;
&lt;BiCart size=&quot;2rem&quot; /&gt;
{!isEmpty &amp;&amp; &lt;span style={{ position: &#39;relative&#39;, left: &#39;-21px&#39;, top: &#39;-18px&#39; }}&gt;{totalItems}&lt;/span&gt;}
&lt;span style={{ marginLeft: !isEmpty ? &#39;-13px&#39; : 0 }}&gt;&amp;nbsp;Cart&lt;/span&gt;
&lt;/Link&gt;
&lt;Link
to=&quot;/wishlist&quot;
className={`${darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;} d-flex align-items-center`}
&gt;
&lt;BiCart size=&quot;2rem&quot; /&gt;
{!isEmpty &amp;&amp; &lt;span style={{ position: &#39;relative&#39;, left: &#39;-21px&#39;, top: &#39;-18px&#39; }}&gt;{count.length}&lt;/span&gt;}
&lt;span style={{ marginLeft: !isEmpty ? &#39;-13px&#39; : 0 }}&gt;&amp;nbsp;Wishlist&lt;/span&gt;
&lt;/Link&gt;
{
isAuthenticated ? (
&lt;&gt;
&lt;button onClick={() =&gt; logout({ logoutParams: { returnTo: window.location.origin } })} className={`login-btn ${darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;}`}&gt;
Log Out
&lt;/button&gt;
&lt;/&gt;
) : (
&lt;&gt;
&lt;button onClick={() =&gt; loginWithRedirect()} className={`login-btn ${darkMode ? &#39;text-dark-primary&#39; : &#39;text-light-primary&#39;}`}&gt;
Log in
&lt;/button&gt;
&lt;/&gt;
)
}
&lt;/Nav&gt;
&lt;/Navbar.Collapse&gt;
&lt;/Container&gt;
&lt;/Navbar&gt;

);
};

export default Header;

ProductCard page:

import React, { useState } from 'react';
import { Button, Card } from 'react-bootstrap';
import { useThemeHook } from '../GlobalComponents/ThemeProvider';
import { useCart } from 'react-use-cart';
import { BsCartPlus } from 'react-icons/bs';
import { Link } from "@reach/router";
import { useInView } from 'react-intersection-observer';

const ProductCard = (props) => {
// const [state,setState]=useState({
// favourites:[]
// });
const [favourites, setFavourites] = useState([]);

let { image, price, title, id } = props.data;
const [theme] = useThemeHook();
const { addItem } = useCart();
const { ref: headerAni, inView: headerAniVisible } = useInView();
const addToCart = () =&gt; {
addItem(props.data);
}
const handleFavourites = (likedItem) =&gt; {
let oldData = JSON.parse(localStorage.getItem(&#39;liked&#39;)) ?? []
if (favourites.includes(likedItem.id)) {
oldData = oldData.filter((m) =&gt; m.id !== likedItem.id)
console.log(&quot;if&quot;, oldData)
} else {
oldData.push(likedItem)
console.log(&quot;else&quot;, oldData)
}
localStorage.setItem(&quot;liked&quot;, JSON.stringify(oldData));
console.log(oldData);
handleFavouritesState();
};
const handleFavouritesState = () =&gt; {
let oldData = JSON.parse(localStorage.getItem(&quot;liked&quot;)) ?? []
let temp = oldData.map((likedItem) =&gt; likedItem.id);
setFavourites([...temp])
console.log(&quot;son&quot;, oldData)
};
return (
&lt;&gt;
&lt;Card
style={{ width: &#39;18rem&#39;, height: &#39;auto&#39; }}
className={`${theme ? &#39;bg-light-black text-light&#39; : &#39;bg-lihgt text-black&#39;} text-center p-0 overflow-hidden shadow mx-auto mb-4`}
ref={headerAni}
&gt;
&lt;Link to={`/product-details/${id}`}&gt;
&lt;div style={{
background: &#39;white&#39;, height: &#39;15rem&#39;, overflow: &#39;hidden&#39;, display: &#39;flex&#39;,
justifyContent: &#39;center&#39;, alignItems: &#39;center&#39;, marginBottom: &#39;inherit&#39;
}}&gt;
&lt;div style={{ width: &#39;9rem&#39; }}&gt;
&lt;Card.Img variant=&quot;top&quot; src={image} className=&quot;img-fluid&quot; data-aos-easing=&quot;ease-out-cubic&quot;
data-aos-duration=&quot;3000&quot; data-aos={`${headerAniVisible ? &quot;&quot; : &quot;zoom-out&quot;}`} /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/Link&gt;
&lt;Card.Body&gt;
&lt;Card.Title style={{ textOverflow: &#39;ellipsis&#39;, overflow: &#39;hidden&#39;, whiteSpace: &#39;nowrap&#39; }}&gt;
{title}
&lt;/Card.Title&gt;
&lt;Card.Title&gt;
$ &lt;del&gt;&lt;span className=&quot;&quot;&gt;{price * 2}&lt;/span&gt;&lt;/del&gt;
&lt;/Card.Title&gt;
&lt;Card.Title&gt;
$ &lt;span className=&quot;h3&quot;&gt;{price}&lt;/span&gt;
&lt;/Card.Title&gt;
&lt;Button
onClick={() =&gt; addToCart()}
className={`${theme ? &#39;bg-dark-primary text-black&#39; : &#39;bg-light-primary&#39;} d-flex align-item-center m-auto border-0`}
&gt;
&lt;BsCartPlus size=&quot;1.8rem&quot; /&gt;
Add to cart
&lt;/Button&gt;
&lt;Button
onClick={() =&gt; handleFavourites(props.data)}
className={`${theme ? &#39;bg-dark-primary text-black&#39; : &#39;bg-light-primary&#39;} d-flex align-item-center m-auto border-0`}
&gt;
&lt;BsCartPlus size=&quot;1.8rem&quot; /&gt;
Add to Favourites
&lt;/Button&gt;
&lt;/Card.Body&gt;
&lt;/Card&gt;
&lt;/&gt;
);

};

export default ProductCard;


</details>
# 答案1
**得分**: 1
以下是您要翻译的内容:
正如评论中提到的那样。您收到警告是因为您存在无限循环,因为您正在监听并更新相同的状态。
以下是您可以尝试的方法。当您点击“添加到愿望清单”时,只需更新您的计数状态。将新项目附加到存储在计数状态中的现有愿望清单。然后,useEffect 将负责将愿望清单添加/同步到本地存储。
```jsx
export default function App() {
// 初始状态将从本地存储中获取愿望清单项目并设置在状态中
const [count, setCount] = useState(JSON.parse(localStorage.getItem("liked")) || []);
// 这是您的添加到愿望清单函数。您可以创建类似的函数来从愿望清单中删除项目。在那种情况下,您只需要过滤计数状态。
const addToWishlist = (item) => {
setCount(prev => [...prev, item]);
};
// 每当状态更改时,这将更新您的本地存储。
useEffect(() => {
localStorage.setItem("liked", JSON.stringify(count));
}, [count]);
return (
<div>
<h1>愿望清单</h1>
<h2>{count.length}</h2>
<button onClick={() => addToWishlist({id: 1, name: 'test'})}>添加到愿望清单</button>
</div>
);
}

希望对您有所帮助。如果您需要进一步的帮助,请告诉我。

英文:

As mentioned in the comments. You are getting warning because you are having infinite loop as you are listening to and updating the same state.

Here is what you can try. When you click Add to wishlist just update your count state. Append new item to your existing wishlist stored in the count state. And then the useEffect will take care of adding/synching wishlist to the localstorage.

export default function App() {
// Initial state will pull wishlist items from localstorage and set it in state
const [count, setCount] = useState(JSON.parse(localStorage.getItem(&quot;liked&quot;)) || []);
// This is your add to wishlist function. You can create similar function to remove item from wishlist. In that case you just need to filter the count state.
const addToWishlist = (item) =&gt; {
setCount(prev =&gt; [...prev, item]);
};
// This will update your localstorage whenever state changes.
useEffect(() =&gt; {
localStorage.setItem(&quot;liked&quot;, JSON.stringify(count));
}, [count]);
return (
&lt;div&gt;
&lt;h1&gt;Wishlist&lt;/h1&gt;
&lt;h2&gt;{count.length}&lt;/h2&gt;
&lt;button onClick={() =&gt; addToWishlist({id: 1, name: &#39;test&#39;})}&gt;Add to Wishlist&lt;/button&gt;
&lt;/div&gt;
);
}

huangapple
  • 本文由 发表于 2023年4月13日 17:28:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76003839.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定