У меня есть этот компонент, который отображает количество людей, которым понравилась книга, однако я не могу получить постоянный результат в своих состояниях.
Вот мой код:
///this is for getting the book details
const {id} = useParams();
const dispatch = useDispatch();
const[hasliked, sethasliked] = useState(null);
useEffect(() => {
const bookData = {
id: id
}
dispatch(openBook(bookData))
}, [])
///and this is for setting the state of the component
const { bookFeatured, isLoading, isSuccess, openbook, likeStatus } = useSelector(state => state.book);
const { user, isError, message } = useSelector(state => state.auth);
useEffect(()=>{
if(openbook.noOfLikes?.find((noOfLikes) => noOfLikes === user._id)){
sethasliked(true)
}else{
sethasliked(false)
}
},[openbook])
const Likes = () => {
return hasliked
? (
<><FaHeart fontSize="small" /> {hasliked.toString()}</>
) : (
<><FaRegHeart fontSize="small" fill='white'/> {hasliked.toString()}</>
);
};
дело в том, что я получаю противоречивый результат при получении значения от const hasliked, если мне уже понравилась книга, иногда она говорит мне, что hasliked ложно, но иногда оно становится истинным, из-за этого я каждый раз получал разные результаты. когда я визуализирую компонент, я думаю, что это как-то связано с задержкой использования эффекта из-за асинхронных действий. Могу ли я что-то с этим сделать?
.toString()
? почему бы просто не сделать
return hasliked
? (
<><FaHeart fontSize="small" />True</>
видя, как hasliked
там уже верно.
else{
sethasliked(false)
}
можно устранить, изменив инициализацию на
const[hasliked, sethasliked] = useState(false);
dispatch(openBook(bookData))
возвращает обещание, вы можете установить hasliked
в блоке .then
, устраняя необходимость во втором эффекте использованияreturn hasliked
к этому
return hasliked && openbook
Вы можете добавить loading state
к своему компоненту и проверить, соответствует ли состояние загрузки true
, а затем показать загрузчик или показать свой компонент.
const {id} = useParams();
const dispatch = useDispatch();
const[hasliked, sethasliked] = useState(null);
const [loading, setLoading] = useState(false) // The loading state
useEffect(() => {
setLoading(true) // Setting the loading state true
const bookData = {
id: id
}
dispatch(openBook(bookData))
}, [])
///and this is for setting the state of the component
const { bookFeatured, isLoading, isSuccess, openbook, likeStatus } = useSelector(state => state.book);
const { user, isError, message } = useSelector(state => state.auth);
useEffect(()=>{
if(openbook.noOfLikes?.find((noOfLikes) => noOfLikes === user._id)){
sethasliked(true)
setLoading(false) // Setting loading state to false
}else{
sethasliked(false)
setLoading(false) // Setting loading state to false
}
},[openbook])
const Likes = () => {
// show a loader if loading is true
if(loading) {
return <div>Loading...</div>
}
return hasliked
? (
<><FaHeart fontSize="small" /> {hasliked.toString()}</>
) : (
<><FaRegHeart fontSize="small" fill='white'/> {hasliked.toString()}</>
);
};
попробовал это, я получаю те же значения (false) для состояния загрузки после возврата div, но значение hasliked по-прежнему несовместимо. Я думаю, что это как-то связано с функцией if(openbook.noOfLikes?.find((noOfLikes) => noOfLikes === user._id)) , она не находит noOflikes мгновенно, я думаю, что перед назначением правильные значения для hasliked , но до сих пор не знаю, как это исправить
Вы пробовали использовать setTimeout?
useEffect( () => {
const tmr = setTimeout( () => {
const bookData = { id: id }
dispatch( openBook(bookData) )
}, 500)
return () => clearTimeout(tmr);
}, [])
useEffect( () => {
const tmr = setTimeout( () => {
if (openbook.noOfLikes?.find( (noOfLikes) => noOfLikes === user._id) ) {
sethasliked(true)
} else { sethasliked( false) }
}, 500)
return () => clearTimeout(tmr);
},[openbook])
Здравствуйте, установка тайм-аута определенно помогает, я не понимаю, почему это происходит, но я не могу найти другого решения проблемы, поэтому я мог бы использовать это, спасибо!
@JASMAL setTimeout определенно будет работать здесь, но это не стандартное решение, потому что оно замедлит работу вашего приложения. Потому что независимо от того, сколько времени займет ваш запрос, он займет минимум 0,5 с, а это нехорошо.
@JASMAL У меня такая же проблема, как и у вас вчера, попробуйте использовать timeout
и вуаля! проблема решена. Я предполагаю, что useEffect
запускается сразу после рендеринга компонента, даже если вы еще не видели этот компонент. в любом случае добро пожаловать!
@DharmikPatel, возможно, будет достаточно изменить интервал на 0,1 с, я лично установил интервал на 50, все еще работает (в моем приложении)
@Musadarj это зависит от того, потому что каждый запрос занимает разное время, поэтому, если запрос не будет завершен за 0,1 с, у него снова будет та же проблема.
@DharmikPatel да, ты определенно прав
для номера 1. я пытаюсь отладить, получаю ли я правильные значения из useState после установки его из useeffect, но кажется, что я получаю противоречивый результат на основе того, что рендерится из этой функции toString, 2. попытался изменить его, но проблема все еще сохраняется ( несоответствующее значение от понравилось) 4. попробовал также. но не решает проблему, я все еще думаю, могу ли я использовать 3, но из того, что я пробовал, я не могу установить состояние в блоке then()