#javascript #reactjs
#javascript #reactjs
Вопрос:
У меня есть следующий API списка сообщений пользователя
[
{
"id": 24,
"url": "http://blablabla/api/v1/postdetail/24"
},
{
"id": 23,
"url": "http://blablabla/api/v1/postdetail/23"
},
{
"id": 22,
"url": "http://blablabla/api/v1/postdetail/22"
},
{
"id": 21,
"url": "http://blablabla/api/v1/postdetail/21"
},
{
"id": 20,
"url": "http://blablabla/api/v1/postdetail/20"
},
]
Я пытался сделать PostList.js
этот файл имеет useEffect, который извлекает Post List API (в результате к API выше)
, а внутри него в JSX есть такой пример кода ниже
PostList.js
function PostList(props) {
const [postList, setPostList] = useState([]);
const [error, setError] = useState('');
useEffect(() => {
console.log(props.posts_api);
axios
.get(`${props.posts_api}`, {
headers: header_in_request,
})
.then((res) => {
setPostList(res.data);
console.log('not errorz');
console.log(res.data);
setError(null);
})
.catch((err) => {
console.log(err.message);
setError(err.message);
});
}, []);
return (
<React.Fragment>
{error == '' ? (
postList.length > 0 ? (
postList.map(function (post) {
return (
// the line where that error had pointed to . after it tried to mount the PostCoba component
<Post key={post.id} post_api={post.url} />
);
})
) : (
<React.Fragment>
<h2>this user has not posted anything yet</h2>
</React.Fragment>
)
) : (
<React.Fragment>
<h2>{error}</h2>
</React.Fragment>
)}
</React.Fragment>
);
}
the Post.js это файл, который извлекает URL-адрес, который был передан.
и отображает его данные Post
Post.js
function Post(props) {
const [postDetail, setPostDetail] = useState({
id: '',
poster: {},
postphoto_set: [],
});
const [error, setError] = useState('');
useEffect(() => {
axios
.get(`${props.post_api}`, {
headers: header_in_request,
})
.then((res) => {
setPostDetail(res.data);
console.log('not errorz');
console.log(res.data);
setError('');
})
.catch((err) => {
console.log(err.message);
setError(err.message);
});
}, []);
return (
<React.Fragment>
{console.log('jsx is running')}
{error == '' ? (
<React.Fragment>
{postDetail.id !== '' ? (
<React.Fragment>
<div className="media border p-3" key={postDetail.id}>
<img
src="img_avatar3.png"
alt="John Doe"
className="mr-3 mt-3 rounded-circle"
style={{ width: '60px' }}
/>
<div className="media-body">
<h4>
{' '}
{postDetail.poster.name}
<small>
<i>{postDetail.created_at}</i>
</small>
</h4>
<h2>{postDetail.title}</h2>
<pre>{postDetail.text}</pre>
<p>amp;#9733; {postDetail.likes_amount} likes</p>
<div className="row">
<div className="col">
{postDetail.likebutton == true ? (
<input
type="image"
src={`${process.env.PUBLIC_URL}/icons/like-blue.png`}
/>
) : (
<input
type="image"
src={`${process.env.PUBLIC_URL}/icons/like-black.png`}
/>
)}
</div>
<div className="col">
<button type="button" className="btn">
Comment
</button>
</div>
<div className="col">
<button type="button" className="btn">
Share
</button>
</div>
</div>
</div>
{
// showcomment == true amp;amp; (
// <CommentList
// comments_api = {post.comments}
// />
// )
}
</div>
</React.Fragment>
) : (
<React.Fragment>
<h2>loading..</h2>
</React.Fragment>
)}
</React.Fragment>
) : (
<h2>{error}</h2>
)}
</React.Fragment>
);
}
export default Post;
но у меня была эта ошибка (см. Прокомментированный код в PostList.js выше, чтобы узнать строку ошибки)
в нем говорится
Не удается выполнить обновление состояния реакции для размонтированного компонента. Это ошибка, но она указывает на утечку памяти в вашем приложении. Чтобы исправить, отмените все подписки и асинхронные задачи в функции очистки useEffect
есть ли какой-либо лучший шаблон кода для отображения каждого из post API внутри PostList API? или есть какой-нибудь способ исправить ошибку? Спасибо
Ответ №1:
Проблема
Мне потребовалось некоторое время, чтобы заметить вашу ошибку. По сути, все сводится к тому, что в JS, '' != null
.
Ваш PostList.js
компонент начинается с error
состояния, установленного на пустую строку. Затем в вашем useEffect()
обратном вызове, который выполняется при монтировании компонента, вы выполняете асинхронный вызов, который завершается успешно и устанавливает состояние массива posts, которое монтирует массив Post.js
компонентов.
Пока все хорошо. Но теперь все начинает идти не так.
Когда Post
компонент монтируется, у него есть свой собственный асинхронный вызов «при монтировании» useEffect()
, который не успевает вернуться раньше…
… выполнение возобновляется при PostList
успешном обратном вызове для вызова API. Затем это устанавливает состояние ошибки в null
. Это заставляет React планировать повторную визуализацию PostList
компонента. Он не запускает эффект снова, но когда он попадает error == ''
в логику рендеринга, он оценивается false
как равный, и выполнение переходит к предложению else тернарного оператора, что выдает ошибку null
. Это также отключает весь массив Post
компонентов.
Вскоре после этого возвращаются вызовы API, выполняемые (теперь размонтированными) Post
компонентами, и выполняются их успешные обратные вызовы, которые включают setPostDetail()
вызов. Но поскольку эти компоненты размонтированы, предупреждение, которое вы видите, регистрируется.
Решение
Немедленное решение — убедиться, что вы вызываете setError('')
not setError(null)
. Но это не решает реальную проблему здесь, которая заключается в отсутствии отмены запросов API в полете, когда ваши компоненты размонтируются.
Для этого используйте axios CancelToken
, который затем можно использовать для отмены запроса (если он еще не завершен) при отключении компонента.
например
useEffect(() => {
console.log(props.posts_api);
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios
.get(`${props.posts_api}`, {
headers: header_in_request,
cancelToken: source.token,
})
.then((res) => {
setPostList(res.data);
console.log('not errorz');
console.log(res.data);
setError('');
})
.catch((err) => {
console.log(err.message);
setError(err.message);
});
// the important bit: returning a way for React to cancel the request.
return () => source.cancel();
}, []);
Дальнейшее чтение
Подробнее о том, почему вы всегда должны возвращать функцию очистки из функций эффектов, которые выполняют что-либо асинхронно, см. В документах React для «Эффектов с очисткой».