javascript - 是否可以将 useEffect 放在 if 语句中?
问题描述
所以,伙计们,我一直在研究我的登陆和仪表板页面。
所以页面的工作流程是这样的:用户进入登陆页面,他可以选择插入表单位置,或者按一个按钮来接收所有位置。现在在后端,我创建了两个 API,一个用于获取所有位置,第二个是我添加:location
的req.body.param
位置,然后根据该参数过滤位置。在邮递员中一切正常。
现在因为我有两种用户获取位置的方式(全部或他想要的一些),所以我认为我useEffect
在 if 语句中放置了两个 s,如下所示:
const filter = props.location.data;
if (filter) {
useEffect(() => {
const fetchFiltered = async () => {
const res = await ArticleService.filterByName(filter);
setContent(res.data);
};
fetchFiltered();
}, []);
} else {
useEffect(() => {
const fetchPosts = async () => {
const res = await ArticleService.articles();
setContent(res.data);
};
fetchPosts();
}, []);
}
所以我背后的逻辑是,如果有filter
内部props.location
执行我useEffect
从ArticleService
谁那里获取数据,然后在 api url 中发送过滤器。如果没有filter
,只需检索我所有的数据,并将内容设置为res.data
.
但是当我编译代码错误是这样的:React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render
是否有某种方法可以使用我的逻辑来执行此操作,或者我需要创建两个组件:一个是普通仪表板,第二个用于过滤结果?
用户发送位置的 Landing.js
<Form>
<div className='form-group'>
<Input
type='text'
className='form-control text-center'
name='name'
placeholder='Enter desired location'
value={location}
onChange={onChangeLocation}
/>
<Link to={{ pathname: '/dashboard', data: location }}>
<i className='fas fa-check'></i>
</Link>
</div>
<p className='text-center'>or</p>
<Link className='btn btn-primary btn-block' to='/dashboard'>
Show all locations
</Link>
</Form>
仪表板.js
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import Pagination from 'react-js-pagination';
import ArticleService from '../../services/article.service';
const Dashboard = (props) => {
const [content, setContent] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage] = useState(10);
const filter = props.location.data;
if (filter) {
useEffect(() => {
const fetchFiltered = async () => {
const res = await ArticleService.filterByName(filter);
setContent(res.data);
};
fetchFiltered();
}, []);
} else {
useEffect(() => {
const fetchPosts = async () => {
const res = await ArticleService.articles();
setContent(res.data);
};
fetchPosts();
}, []);
}
let counter = content.length;
// Get current posts
const indexOfLastPost = currentPage * postsPerPage;
const indexOfFirstPost = indexOfLastPost - postsPerPage;
const currentPosts = content.slice(indexOfFirstPost, indexOfLastPost);
// Change page
const handlePageChange = (pageNumber) => {
setCurrentPage(pageNumber);
};
const render = (item, index) => {
return (
<tr key={index}>
<td className='text-center'>
<div key={item.id}>
<img
src={`${item.pictures}`}
alt='slika artikla'
className='rounded'
></img>
</div>
</td>
<td className='text-center'>
<div key={item.id}>
<h4>{item.descr}</h4>
<br></br>
<h6 className='text-left'>Number of m2: {item.sqm}m2</h6>
<div className='text-left'>
<small className='text-left'>
{' '}
<a href={item.link} target='_blank' rel='noopener noreferrer'>
Show on website
</a>
</small>
</div>
</div>
</td>
<td className='text-center'>
<div key={item.id}>
<h4>{item.price}</h4>
<small className='text-left'>Price per m2: {item.ppm2}</small>
</div>
</td>
<td className='text-center'>
<div key={item.id}>
<Link to={`/article/${item.id}`}>
<h4>Show</h4>
</Link>
</div>
</td>
</tr>
);
};
return (
<div>
<div className='container'>
<h4 className='text-center'>
Number {counter}
</h4>
<div className='table-responsive'>
<table className='table'>
<thead className='thead-dark'>
<tr>
<th className='text-center' scope='col'>
Pic
</th>
<th className='text-center' scope='col'>
Description
</th>
<th className='text-center w-25' scope='col'>
Price
</th>
<th className='text-center' scope='col'>
Show offer
</th>
</tr>
</thead>
<tbody>{currentPosts.map(render)}</tbody>
</table>
</div>
</div>
<nav>
<div className='w3-bar w3-xlarge'>
<ul className='pagination justify-content-center'>
<li className='page-item'>
<Pagination
hideDisabled
hideNavigation
hideFirstLastPages
currentPage={currentPage}
itemsCountPerPage={10}
totalItemsCount={content.length}
pageRangeDisplayed={indexOfLastPost}
onChange={handlePageChange}
/>
</li>
</ul>
</div>
</nav>
</div>
);
};
export default Dashboard;
谢谢!:D
解决方案
基本答案,不,你不能有条件地调用useEffect。您必须将条件逻辑放在 useEffect 回调中。
const filter = props.location.data
useEffect(() => {
if (filter) {
const fetchFiltered = async () => {
const res = await ArticleService.filterByName(filter)
setContent(res.data)
}
fetchFiltered()
} else {
const fetchPosts = async () => {
const res = await ArticleService.articles()
setContent(res.data)
}
fetchPosts()
}
}, [filter, setContent, ArticleService.filterByName, ArticleService.articles])
React 中的 Hooks 并不真正遵循 javascript 的标准规则。它们必须实现的方式存在性能原因,通常会进行一些缓存以阻止每次渲染过程完成时执行的多余代码。
useEffect 挂钩只会在依赖数组中的一个值(useEffect 的第二个参数)发生更改的渲染期间运行其回调函数。输入所有可能改变的外部值是标准的。因此,当 filter 的值发生变化时,应用程序将重新渲染,useEffect 将进行比较,意识到某些内容已更改并运行它再次回调,然后执行 if 语句。
您可以在文档的性能部分阅读更多相关信息
推荐阅读
- python - 重新标记熊猫中的值
- laravel - Laravel 5.6 空字段验证
- android - 仅当用户单击编辑文本框以插入文本时如何显示键盘?
- php - 在 CodeIgniter 中验证失败时重定向特定错误的页面
- json - 通过 Dictionary 对象解析 Json 响应
- python - 在 python、matplotlib、多臂老虎机中绘制正态分布
- angular - Typescript - 在运行时检查类型并警告错误
- c# - 使用 linq 检查 IEnumerable 列表的计数
- r - 如何在 R 中分组并作为列表返回?
- angular - 如何在 SVG 路径中使用 routerLink?