React 函数组件不会更新视图 onClick
React Function Component doesn't update view onClick
我是 React 新手。我有一个我创建的评级组件。我遇到的问题是 onClick 我可以看到评级在控制台中更新,但在页面上我没有看到发生变化。我的理解是 React 组件需要是纯函数,并且最好选择函数式组件而不是 类。当我尝试使用 useState 挂钩时,我的评分被添加到之前的状态并且没有在页面上正确更新。
我的第一个问题是 best/preferred 在组件内更新状态的方法是什么?
如果我使用的是功能组件,是否必须使用挂钩?
请看下面我的代码
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>
</>
)
}
如果我点击第四颗星,这会按预期返回,但 UI 不会更新。
正如您所建议的,您将需要使用挂钩来寻找您正在寻找的功能(或使用 class 组件)。在您当前的实现中,您实际上并没有使用 React 状态,因此 React 不知道您希望它重新渲染您的组件。此外,您在 rate() 中使用的 stars 数组与组件中的 stars 数组不同。您似乎没有使用 rate()
创建和返回的星数组
您究竟是如何尝试使用 useState 的?
这是一个工作版本,它使用 useState
和 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>
所以,看来我需要使用useState hook。我敢肯定还有另一种方法可以做到这一点,但这对我有用。
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>
</>
)
}
我是 React 新手。我有一个我创建的评级组件。我遇到的问题是 onClick 我可以看到评级在控制台中更新,但在页面上我没有看到发生变化。我的理解是 React 组件需要是纯函数,并且最好选择函数式组件而不是 类。当我尝试使用 useState 挂钩时,我的评分被添加到之前的状态并且没有在页面上正确更新。
我的第一个问题是 best/preferred 在组件内更新状态的方法是什么? 如果我使用的是功能组件,是否必须使用挂钩?
请看下面我的代码
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>
</>
)
}
如果我点击第四颗星,这会按预期返回,但 UI 不会更新。
正如您所建议的,您将需要使用挂钩来寻找您正在寻找的功能(或使用 class 组件)。在您当前的实现中,您实际上并没有使用 React 状态,因此 React 不知道您希望它重新渲染您的组件。此外,您在 rate() 中使用的 stars 数组与组件中的 stars 数组不同。您似乎没有使用 rate()
创建和返回的星数组您究竟是如何尝试使用 useState 的?
这是一个工作版本,它使用 useState
和 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>
所以,看来我需要使用useState hook。我敢肯定还有另一种方法可以做到这一点,但这对我有用。
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>
</>
)
}