我正在尝试在组件中使用React挂钩(useState和useEffect)来显示投票计数。用户单击上/下后,“ vote”状态应递增或递减,然后应用程序将对数据库中的“ vote”计数进行API调用PATCH。原始投票计数来自父组件传递的道具。但是出于某种原因,投票的初始状态始终为0-即使当我console.log道具时,投票显示的是正确的投票数?
PATCH请求似乎工作正常,但是带有钩子的东西我认为是错误的。在此先感谢您提供的任何帮助!
export default function Votes(props) {
const { item, voteCount, itemType } = props
const [votes, setVotes] = useState(voteCount || 0)
useEffect(() => {
if (itemType == 'question') {
questionApiService.updateQuestionFields({
questionId: item.id,
questionFields : { votes: `${votes}` }
})
} else if (itemType === 'answer') {
console.log('answer')
// questionApiService.updateAnswerFields({
// answerId: item.id,
// answerFields: { votes: votes }
//})
}
}, [votes])
const handleClick = e => {
e.currentTarget.id === "increment"
? setVotes(prevCount => prevCount + 1)
: setVotes(prevCount => prevCount - 1)
}
return (
<div className="QuestionPage__votes-count">
<button id="increment" onClick={handleClick}>
<FontAwesomeIcon icon={faCaretUp} size="2x" />
</button>
{votes}
<button id="decrement" onClick={handleClick}>
<FontAwesomeIcon icon={faCaretDown} size="2x" />
</button>
</div>
)
}
答案 0 :(得分:0)
您需要将itemType
添加到useEffect
的依赖项中,因为您不能期望道具在最初的渲染中就可用,或者不能在组件的整个生命周期中保持静态。在您当前的示例中,引用的itemType
将始终在该函数首次运行时引用其值。
正如其他人提到的那样,通过props设置状态初始值是不行的。您可以通过在组件收到其道具后使用单独的Effect来设置状态来解决此问题:
...
const [votes, setVotes] = useState(0);
...
useEffect(() => {
setVotes(voteCount);
}, [voteCount]);
答案 1 :(得分:0)
您可以使用useState()
,如@tobiasfreid所说的那样更改计数器状态,或者如果您想创建自定义钩子来实现相同的功能。
function ChangeCounter() {
const [counter,onChangeValue] = useCounter(0);
return (
<div className="Form">
<button type="button" onClick={onChangeValue(counter + 1)}> Increase Counter </button>
</div>
);
}
function useCounter(initialValue){
const [value, setValue] = useState(initialValue || 0);
const onChange= (data) => {
setValue(data)
};
return [value, onChange];
}
通过这种方式,您可以创建自定义钩子。
答案 2 :(得分:0)
import React from 'react';
import ReactDOM from 'react-dom';
function useCounter(initialCount = 0) {
const [count, setCount] = React.useState(initialCount);
const increment = React.useCallback(() => setCount(c => c + 1), []);
const decrement = React.useCallback(() => setCount(c => c - 1), []);
return { count, increment, decrement };
}
const delay = duration => new Promise(resolve => setTimeout(resolve, duration));
function App() {
const { count: votes, increment, decrement } = useCounter(0);
React.useEffect(() => {
(async () => {
console.log('Call your API');
await delay(2000);
console.log('API Called with votes :', votes);
})();
}, [votes]);
return (
<div>
<h1>Votes {votes}</h1>
<button onClick={decrement}>Decrement</button>
<button onClick={increment}>Increment</button>
</div>
);
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
答案 3 :(得分:0)
tobiasfried的回答确实帮助了我。我将在此处发布完整的解决方案代码,以防将来对其他人有帮助。当然,如果有人对改进此代码有建议,我希望听到他们的声音。
export default function Votes(props) {
const { item, itemType } = props
const [votes, setVotes] = useState()
useEffect(() => {
setVotes(item.votes);
}, [item.votes])
useEffect(() => {
if (itemType == 'question') {
questionApiService.updateQuestionFields({
questionId: item.id,
questionFields : { votes: votes }
})
} else if (itemType === 'answer') {
// questionApiService.updateAnswerFields({
// answerId: item.id,
// answerFields: { votes: votes }
//})
}
}, [votes, itemType])
return (
<div className="QuestionPage__votes-count">
<button
onClick={() => setVotes(prevCount => prevCount + 1)}>
<FontAwesomeIcon icon={faCaretUp} size="2x" />
</button>
{votes}
<button
onClick={() => setVotes(prevCount => prevCount - 1)}>
<FontAwesomeIcon icon={faCaretDown} size="2x" />
</button>
</div>
)
}