Soy nuevo en Reaccionar. Tengo un componente de calificación que creé. El problema que tengo es onClick. Puedo ver que la calificación se actualiza en la consola, pero en la página no veo que ocurra el cambio. Según tengo entendido, los componentes de React deben ser funciones puras y es mejor preferir los componentes funcionales a las clases. Cuando trato de usar el enlace useState, mi calificación se agrega al estado anterior y no se actualiza correctamente en la página.
Mi primera pregunta es ¿cuál es la forma mejor/preferida de actualizar el estado dentro de un componente? Si estoy usando un componente funcional, ¿tengo que usar un gancho?
Por favor vea mi código abajo
export default function Rating(props) { let stars = []; // const [stars, setStars] = useState([]); let star = '☆'; for (let i = 0; i < props.stars; i++) { stars.push(star); } function rate(index) { let filledStar = '★' let stars = []; // setStars([]) for (let i = 0; i < props.stars; i++) { stars.push(star); } stars.forEach((star, i) => { while (index >= 0) { stars[index] = filledStar; index--; } }) console.log('stars filled', stars) return stars } return ( <> <div className="stars"> {stars.map((star, i) => ( <h2 key={i} onClick={() => rate(i)}>{star} </h2> ))} </div> </> ) }Si hago clic en la cuarta estrella, se devuelve como se esperaba, pero la interfaz de usuario no se actualiza.
Aquí hay una versión de trabajo que completa las estrellas hasta la estrella en la que se hizo clic, inclusive, usando useState y useEffect .
const { Fragment, useEffect, useState } = React; function Rating(props) { // Set state as an empty array const [stars, setStars] = useState([]); // Called by useEffect his function // creates a new array of empty stars function initStars() { const stars = []; for (let i = 0; i < +props.stars; i++) { stars.push('☆'); } setStars(stars); } // Called when the component // first mounts, and called only once useEffect(() => { initStars(); }, []); function rate(e) { // Get the id from the star dataset const { id } = e.target.dataset; // Create a fresh array const stars = []; // Loop; if the current index is less or // equal to the id set it as a filled star // otherwise set it to an empty star for (let i = 0; i < +props.stars; i++) { stars.push(i <= +id ? '★' : '☆'); } // Set the state with the new array setStars(stars); } return ( <div> {stars.map((star, i) => ( <span className="star" key={i} data-id={i} onClick={rate} >{star} </span> ))} </div> ); }; ReactDOM.render( <Rating stars="10" />, document.getElementById('react') ); .star { font-size: 1.8em; } .star:hover { cursor: pointer; } <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script> <div id="react"></div>Entonces, parece que necesito usar el gancho useState. Estoy seguro de que hay otra manera de hacer esto, pero esto funcionó para mí.
export default function Rating(props) { const [stars, setStars] = useState([]); let star = '☆'; function initStars() { const stars = []; for (let i = 0; i < props.stars; i++) { stars.push(star); } setStars(stars); } // Called when the component // first mounts, and called only once useEffect(() => { initStars(); }, []); function rate(index) { console.log('index', index); let filledStar = '★' let stars = []; console.log('setStars', stars); for (let i = 0; i < props.stars; i++) { stars.push(star); } stars.forEach((star, i) => { while (index >= 0) { stars[index] = filledStar; index--; } }) console.log('stars filled', stars) // return stars setStars(stars) } // console.log('stars', stars); return ( <> <div className="stars"> {stars.map((star, i) => ( <h2 key={i} onClick={() => rate(i)}> {star} </h2> ))} </div> </> ) }Como sugirió, necesitará usar ganchos para buscar la funcionalidad que está buscando (o usar un componente de clase). En su implementación actual, en realidad no está utilizando los estados de React, por lo que React no sabe que desea volver a renderizar su componente. Además, la matriz de estrellas que está utilizando en rate() es diferente de la matriz de estrellas en su componente. Parece que no estás haciendo uso de la matriz de estrellas creada y devuelta por rate()
¿Cómo has intentado usar useState exactamente?