我应该在哪里声明在 useEffect() 钩子中调用的函数?
Posted
技术标签:
【中文标题】我应该在哪里声明在 useEffect() 钩子中调用的函数?【英文标题】:Where should I declare functions that are called inside a useEffect() hook? 【发布时间】:2019-11-12 23:13:27 【问题描述】:所以我在使用useEffect
调用依赖于状态的函数时出现以下情况。
示例:
// INSIDE APP COMPONENT
const [someState, setSomeState] = React.useState(0);
const [someTrigger, setSomeTrigger] = React.useState(false);
function someFunction()
return someState + 1;
React.useEffect(() =>
const newState = someFunction(); // 'someFunction' IS BEING CALLED HERE
setSomeState(newState);
,[someTrigger])
问题:
在这种情况下,我应该在 useEffect()
内声明 someFunction
还是将其放在外面(但在组件的主体内)是否安全?
我可以将它添加到 dependency
数组中,但这会损害我的代码的可重复性,因为我想专注于 trigger
。
由于useEffect()
将在新渲染后运行,是否可以安全地假设它将拥有我在其中调用的函数的新副本?
是否有基本规则说明何时应在 useEffect
挂钩中声明函数,或者何时必须将其添加到依赖项数组中?
编辑:请注意,useEffect
必须拥有这些函数的新副本,因为这些函数需要访问一些最新的 state
变量。
注意:
此代码在 CodeSandbox 上触发以下 eslint 警告。虽然它工作得很好。
React Hook React.useEffect 缺少一个依赖项:'someFunction'。要么包含它,要么删除依赖数组。 (react-hooks/exhaustive-deps)eslint
真实案例:
这是一个简化的例子。在我的真实案例中,这是一个带有过滤器组件的产品搜索页面。所以当我点击一个过滤器来激活它时(比如说,price <= 50
),我触发了一个useEffect()
,它正在“监听”activePriceFilters
状态变量。然后,该效果调用一个函数(在示例中为 someFunction
),该函数将计算 filteredList
并将新的 productList
状态设置为新的 filteredList
。
片段
function App()
const [someState, setSomeState] = React.useState(0);
const [someTrigger, setSomeTrigger] = React.useState(false);
function someFunction()
return someState + 1;
React.useEffect(() =>
const newState = someFunction();
setSomeState(newState);
,[someTrigger])
return(
<React.Fragment>
<div>I am App</div>
<div>My state: someState</div>
<button onClick=()=>setSomeTrigger((prevState) => !prevState)>Click</button>
</React.Fragment>
);
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
【问题讨论】:
您可以阅读this FAQ answer。另外,this is an awesome article 关于useEffect
【参考方案1】:
在 useEffect 内部还是外部定义函数取决于调用所有函数的位置。
如果您的函数仅在 useEffect 中被调用,那么在 useEffect 中定义它是有意义的。
但是,从 useEffect 以及其他事件处理程序或其他效果中调用相同的函数,您需要在 useEffect 之外定义它
附言。在您的情况下,您只是在更新不需要为其定义单独函数的状态
function App()
const [someState, setSomeState] = React.useState(0);
const [someTrigger, setSomeTrigger] = React.useState(false);
React.useEffect(() =>
setSomeState(oldState => oldState + 1);
,[someTrigger])
return(
<React.Fragment>
<div>I am App</div>
<div>My state: someState</div>
<button onClick=()=>setSomeTrigger((prevState) => !prevState)>Click</button>
</React.Fragment>
);
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
就你的场景而言,你会这样写
useEffect(() =>
const calcVal = (oldState) =>
// calculate previous state based on oldState
setSomeState(calcVal);
, [activePriceFilters])
【讨论】:
这个例子是我真实案例场景的过度简化版本。 你能帮助我的真实案例吗?这是一个带有过滤器组件的产品搜索页面。所以当我点击一个过滤器来激活它时(比如说,价格 正如我所说,如果该函数将在 useEffect 之外使用,则需要在 useEffect 之外定义一个单独的函数,否则在 useEffect 中定义它并将其传递给状态更新 谢谢!但是从我的整体代码模式来看,您认为这是一个好方法吗?使用useEffect
来“监听”状态过滤器变量的变化并调用一个为 filteredList
设置新状态的函数?抱歉打扰你。你的回答真的很有帮助。【参考方案2】:
设置另一个状态根本不应该是一个效果。
const [someState, setSomeState] = React.useState(0);
function incrementState()
setSomeState(someState => someState + 1);
【讨论】:
你能帮助我的真实案例吗?这是一个带有过滤器组件的产品搜索页面。所以当我点击一个过滤器来激活它时(比如说,price <= 50
),我触发了一个useEffect()
,它正在“监听”activePriceFilters
状态变量。然后该效果调用一个函数(在示例中为someFunction
),该函数将计算filteredList
并将新的productList
状态设置为新的filteredList
。这种方法有什么问题吗?你会怎么处理这个?谢谢!
是否同步计算?还是从服务器检索它们?
它是同步的。我还应该补充一点,我有超过 1 个组件过滤器,以及超过一个具有不同有源过滤器的状态变量。如果其中任何一个发生变化,我应该计算一个新的 filteredList
状态,它作为道具传递给我的 ResultList
组件。
那我就做const [filters, setFilters] = useState([]); const result = data.filter(filters /*...*/);
是的,在这种情况下。以上是关于我应该在哪里声明在 useEffect() 钩子中调用的函数?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用/不使用 useEffect 钩子在 React JS 函数中获取更改的(新)状态值?