简体   繁体   English

如何避免与 React 挂钩相关的范围界定问题

[英]How can I avoid scoping problems related to React hooks

The Problem问题

I have a recurring problem that seems to happen whenever I try and do anything remotely complicated and async using hooks.我有一个反复出现的问题,每当我尝试使用钩子做任何远程复杂和异步的事情时似乎都会发生。

The timeline which causes the issue goes something like this:导致问题的时间线是这样的:

  1. Define some state in a hook s在钩定义一些状态s
  2. Make an async call to get some data d and use it to set state s进行异步调用以获取一些数据d并使用它来设置状态s
  3. Make a subsequent call based on d , and use it to update s基于d进行后续调用,并使用它来更新s

The problem is that at 3.;问题是在 3.; when I want to update the state s , it at that point is the s as it was defined in the scope at which the function was defined, ie.当我想更新状态s ,它是在定义函数的范围内定义的s ,即。 it has no concept of the latest updated state, only that which it knew about when the function was defined.它没有最新更新状态的概念,只有它在定义函数时知道的状态。

My Half-Solutions我的半解

I have been able to get around this using a few things, a couple of things which tend to work:我已经能够使用一些东西来解决这个问题,一些东西往往有效:

  1. Denormalise state (probably a good idea anyway) such that we avoid as much as possible having to update existing items in state非规范化状态(无论如何可能是个好主意),这样我们就可以尽可能避免更新状态中的现有项目
  2. Run the update after an timeout;超时后运行更新; use setTimeout to force the update to happen in the next render cycle使用setTimeout强制更新发生在下一个渲染周期
  3. Forget using state hooks at all, manage state externally and pass everything in as props完全忘记使用状态挂钩,在外部管理状态并将所有内容作为道具传递

These aren't always (or ever) either good or desirable solutions.这些并不总是(或永远)不是好的或理想的解决方案。 I'm guessing I'm missing something fundamental here but I haven't been able to find anything about this online, and I haven't yet had any viable suggestions from my colleagues.我猜我在这里遗漏了一些基本的东西,但我在网上找不到任何关于这个的东西,我还没有从我的同事那里得到任何可行的建议。

TL:DR翻译:博士

Functions defined within the body of a React functional component will be defined with the scope to which they have access at that time.在 React 功能组件的主体中定义的函数将使用它们当时可以访问的范围来定义。 This isn't always the latest state.这并不总是最新的状态。 How can I get around the problem?我怎样才能解决这个问题?


An arbitrary example to demonstrate what it is I'm talking about:一个任意示例来演示我在说什么:

 const getUsers = () => Promise.resolve({ 1: { name: 'Mr 1', favouriteColour: null, }, 2: { name: 'Ms 2', favouriteColour: null, }, }); const getFavouriteColorForUser = (id) => Promise.resolve({ id, color: Math.random() > 0.5 ? 'red' : 'blue' }); const App = () => { const [users, setUsers] = React.useState({}); const handleClick = () => { getUsers() .then(data => { setUsers(data); return Promise.resolve(data); }) .then(data => { return Promise.all(Object.keys(data).map(getFavouriteColorForUser)); }) .then(data => { const updatedUsers = { ...users, ...data.reduce( (p, c) => ({ ...p, [c.id]: { ...users[c.id], favouriteColor: c.color }, }), {} ) }; console.log('users:'); console.dir(users); console.log('color data:'); console.dir(data); console.log('updatedUsers:'); console.dir(updatedUsers); setUsers(updatedUsers); }) } return ( <div> {Object.keys(users).map(k => users[k]).map(user => ( <div>{user.name}'s favourite colour is {user.favouriteColour}</div> ))} <button onClick={handleClick}>Get Users</button> </div> ); } ReactDOM.render(<App />, document.getElementById('app'))
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script> <div id="app"></div>

setState has a variant where you pass it a function. setState 有一个变体,您可以在其中传递一个函数。 That function is guaranteed to be called with the most recent value from the state.保证使用状态中的最新值调用该函数。 You can use that to calculate your next state:你可以用它来计算你的下一个状态:

.then(data => {
  setUsers(previousUsers => {
    const updatedUsers = {
      ...previousUsers, // <--- using previousUsers, not users
      ...data.reduce(
        (p, c) => ({
          ...p,
          [c.id]: {
            ...previousUsers[c.id], // <--- using previousUsers, not users
            favouriteColor: c.color
          },
        }), {})
    };

    return updatedUsers;
  })
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用钩子根据 REACT 中的特定条件设置与按钮相关的功能以启动、暂停间隔? - How can i set a fucntion related to a button to start , pause Interval according to certain condition in REACT using hooks? 如何在 React 中使用钩子绑定函数? - How can I bind function with hooks in React? 如何避免循环和条件中的 React Hooks? - How to avoid React Hooks inside loops and conditions? 如何使用 React Hooks 避免 memory 泄漏 - How to avoid memory leaks with React Hooks 我如何在 React 经典的 `class` 组件中使用 React hooks? - How can I use React hooks in React classic `class` component? 在通过 React 钩子中的 useEffects 中的多个异步函数获取数据时,我必须指定唯一的 Loading 布尔值以避免并发问题吗? - Must I specify unique Loading booleans when fetching data via multiple async functions within useEffects in React hooks to avoid concurrency problems? 在 React 钩子中排序后如何渲染数组 - How can I render array after sorting in React hooks 如何防止在React中使用钩子重新渲染页面? - How can I prevent re-rendering of the page with hooks in React? 我如何使用带有本机 SSR(没有 NextJS)的反应钩子? - How i can use react hooks with native SSR (without NextJS)? 如何重写组件的一部分以响应钩子 - How can I rewrite part of the component to react hooks
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM