混淆了`.then()`链。

huangapple go评论70阅读模式
英文:

Confusion with .then() chaining

问题

我一直在尝试理解 Promises/then-ables 如何工作。
我正在使用 NextJS。

尝试链式操作以执行以下操作:

  1. 从API获取数据
  2. 保存数据
  3. 修改数据以创建组件
    (并且不产生无限循环)

我无法获取适当的数据来执行步骤#3。
我尝试了各种方法,但卡在这一步。

我正在使用 useEffect,因为这样做(尽管我确信还有其他方法可以实现):
https://nextjs.org/docs/basic-features/data-fetching/client-side

export default function Survey() {
  const [dataDB, setDataDB] = useState('');
  let roles = [];

  function createCards(rolesArr) {

    let role1 = tabs.find(x => x.id == rolesArr[0])
    let role2 = tabs.find(x => x.id == rolesArr[1])
    let role3 = tabs.find(x => x.id == rolesArr[2])

    // 上面的是空的
    // 下面的也是空的:
    //     let role1 = tabs.find(x => x.id == dataDB[0])

    roles.push(role1)
    roles.push(role2); 
    roles.push(role3); // 组件将遍历这3个
  }

  useEffect(() => {
    fetch('example.com/api')
      .then((response) => response.json()) // 1. 获取像[0, 3, 5]这样的数组
      .then((data) => {
        setData(dataDB) // 2. 使用 hook 设置数据,稍后将存储在数据库中
      }
     .then((rolesArr) => createCards(rolesArr)) // 3. 修改数据以供组件使用
    })
  )  

  return ( 
    { 
      roles.map((path) => (
        <Card key={path.id}>
          <Text>{path.title}</Text>
        </Card>
      ))
    } 
  )
}
英文:

I've been trying to understand how Promises/then-ables work for awhile now.
I'm working with NextJS.

Trying to chain together to do the following:

  1. Get data from API
  2. Save the data
  3. Modify the data to create component
    (And not infinite loop)

I can't get the proper data to do step #3.
I've tried various things but am stuck on this step.

I'm using useEffect because of this (though I'm sure there's other ways to do it):
https://nextjs.org/docs/basic-features/data-fetching/client-side

export default function Survey() {
  const [dataDB, setDataDB] = useState(&#39;&#39;);
  let roles;

  function createCards(rolesArr) {

    let role1 = tabs.find(x =&gt; x.id == rolesArr[0])
    let role2 = tabs.find(x =&gt; x.id == rolesArr[1])
    let role3 = tabs.find(x =&gt; x.id == rolesArr[2])

    // the above is null
    // the below is also null:
    //     let role1 = tabs.find(x =&gt; x.id == dataDB[0])

    roles.push(role1)
    roles.push(role2); 
    roles.push(role3); // component will map over these 3
  }

  useEffect(() =&gt; {
    fetch(&#39;example.com/api&#39;)
      .then((response) =&gt; response.json()) // 1. Gets an array like [0, 3, 5]
      .then((data) =&gt; {
        setData(dataDB) // 2. Using hook to setData, will store in database later
      }
     .then((rolesArr) =&gt; createCards(rolesArr)) // 3. Modify data for component
    })
  )  

  return ( 
    { 
      roles.map((path) =&gt; (
        &lt;Card key={path.id}&gt;
          &lt;Text&gt;{path.title}&lt;/Text&gt;
        &lt;/Card&gt;
      ))
    } 
  )
}

答案1

得分: 1

你在这里有很多问题。

roles 未定义

let roles; 创建了一个变量并将其值设置为 undefined

下一次你使用它(这里:roles.map((path) => (),你尝试将其视为数组。

这将导致错误。

你需要在定义时将其设置为一个数组。

拼写错误

> .then((data) => {
> setData(dataDB) // 2. 使用 hook 设置数据,稍后将存储在数据库中
> }

你漏掉了一个 )

rolesArrundefined

以下代码块的返回值:

> .then((data) => {
> setData(dataDB) // 2. 使用 hook 设置数据,稍后将存储在数据库中
> }

… 是 undefined,因为你没有 return 语句,所以链中的下一个 then() 回调将接收到 undefined

然而 你没有做任何需要你创建新的 Promise 的事情,所以没有必要使用额外的 then,只需在你已有的函数中完成所有你想要处理数据的工作。

  .then((data) => {
    setData(dataDB);
    createCards(dataDB);
  });

createCards 修改一个不存在且没有被任何地方使用的数组

> roles.push(role1)
> roles.push(role2);
> roles.push(role3); // 组件将遍历这 3 个

你在这里有与之前相同的问题;roles 不是一个数组,它是 undefined

而且,由于 createCards 是异步调用的,这段代码将在 roles.map((path) => ( 之后运行,所以没有东西会关注这个修改。

不要修改不存在的数组。创建一个新的数组并将其存储在状态中。设置状态将触发重新渲染,所以组件将从状态存储中提取数组并有一些值进行迭代。

通常你会想要做类似于:

const [roles, setRoles] = useState(null);

function createCards(rolesArr) {
    // 等等
    setRoles([role1, role2, role3]);
}

// 等等

如果 `roles` 为 `null`,则返回 <p>Loading</p>;

return roles.map(等等等等);
英文:

You have a lot of problems here.

roles is undefined

let roles; creates a variable and sets its value to undefined.

The next time you touch it (here: roles.map((path) =&gt; () you are trying to treat it as an array.

This will error.

You need to make it an array when you define it.

a typo

> .then((data) => {
> setData(dataDB) // 2. Using hook to setData, will store in database later
> }

You are missing a ) from the end of there

rolesArr is undefined

The return value of:

> .then((data) => {
> setData(dataDB) // 2. Using hook to setData, will store in database later
> }

… is undefined because you have no return statement, so the next then() callback in the chain gets passed undefined.

However you aren't doing anything that requires you to create a new promise there, so there's no point in using an extra then, just do everything you want to do with the data in the function you already have.

  .then((data) =&gt; {
    setData(dataDB);
    createCards(dataDB);
  });

createCards modifies an array that doesn't exist and that nothing uses

> roles.push(role1)
> roles.push(role2);
> roles.push(role3); // component will map over these 3

You have the same problem here that you did earlier; roles isn't an array, it is undefined.

What's more, because createCards is called asynchronously, this code will run after roles.map((path) =&gt; ( so nothing is going to pay attention to the mutation anyway.

Don't mutate the non-existent array. Create a new one and store it in a state. Setting a state will trigger a re-render so the component will pull the array out of the state storage and have some values to iterate over.

Typically you would want to do something like:

const [roles, setRoles] = useState(null);

function createCards(rolesArr) {
    // etc
    setRoles([role1, role2, role3]);
}

// etc

if (roles === null) {
    return &lt;p&gt;Loading&lt;/p&gt;;
}

return roles.map(etc etc);

答案2

得分: 0

使用.then()时,如果要链式使用一个或多个.then(),需要从前一个回调函数返回生成的值。例如:

fetchData()
  .then((response) => {
    console.log(response.json())
    return response.json()
  }).then((values) => {
    console.log(values)
    return values.filter((value) => value > 0)
  }).then((positiveValues) => {
    console.log(positiveValues)
    return positiveValues;
  })

这个示例将打印response.json()并将其作为值返回,以便在下一个.then()回调中使用。

对于您的情况,可以像这样在第二个回调中返回值:

fetch('example.com/api')
  .then((response) => response.json()) // 1. 获取一个类似 [0, 3, 5] 的数组
  .then((data) => {
    setData(dataDB) // 2. 使用 hook 来设置数据,稍后将存储到数据库中
    return dataDB;
  }).then((rolesArr) => createCards(rolesArr)) // 3. 修改组件的数据
英文:

When using the .then(), you need to return the resulting value from the previous callback function if you want to chain one or more .then(). As an example:

fetchData()
  .then((response) =&gt; {
    console.log(response.json())
    return response.json()
  }).then((values) =&gt; {
    console.log(values)
    return values.filter((value) =&gt; value &gt; 0)
  }).then((positiveValues) =&gt; {
    console.log(positiveValues)
    return positiveValues;
  })

This example will print the response.json() and return it as a value to be used as an argument on the next .then() callback.

For your case, return the value inside the second callback like this:

    fetch(&#39;example.com/api&#39;)
      .then((response) =&gt; response.json()) // 1. Gets an array like [0, 3, 5]
      .then((data) =&gt; {
        setData(dataDB) // 2. Using hook to setData, will store in database later
        return dataDB;
      }).then((rolesArr) =&gt; createCards(rolesArr)) // 3. Modify data for component
    })

huangapple
  • 本文由 发表于 2023年3月7日 04:02:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75655331.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定