【问题标题】:How to async await in react render function?如何在反应渲染功能中异步等待?
【发布时间】:2019-05-18 02:15:14
【问题描述】:

我对@9​​87654321@ 非常熟悉,但对后端nodejs 很熟悉。但是我遇到了一个场景,我必须在前端使用它。

我得到了一系列对象,在这些对象中我得到了lat lng 的地方。现在使用react-geocode 我可以获得单个lat lng 的地名,但我想在地图函数中使用它来获取地名。所以正如我们所知,async 打电话我必须在那边使用async await

这里是代码

import Geocode from "react-geocode";
render = async() => {
  const {
    phase,
    getCompanyUserRidesData
  } = this.props   
                      
  return (
    <div>
       <tbody>                   
        await Promise.all(_.get(this.props, 'getCompanyUserRidesData', []).map(async(userRides,index) => {
          const address = await Geocode.fromLatLng(22.685131,75.873468)
          console.log(address.results[0].formatted_address)                         
         return ( 
          <tr key={index}>
            <td>
            {address.results[0].formatted_address}
            </td>
            <td>Goa</td>
            <td>asdsad</td>
            <td>{_.get(userRides,'driverId.email', '')}</td>
            <td>{_.get(userRides,'driverId.mobile', '')}</td>
          </tr>
        )
        }))
      </tbody>
    </div>
  )
}

但是当我在这里使用 async 和 map 函数时,它不会返回任何内容。谁能帮我看看哪里出错了?

【问题讨论】:

  • render 函数将 UI 呈现给浏览器,所以这不是您想要进行异步调用的地方
  • 那么还有其他方法可以解决吗?
  • @Profer 是的。让它成为父组件的状态,一旦设置状态(即异步数据进入),就会有条件地呈现子组件。这在任何 React 应用程序中都是相当标准的,并且 IIRC 早在官方教程中(我可能记错了)。
  • @JaredSmith 你能举个例子吗?顺便说一句,IIRC 是什么?
  • @Profer 如果我没记错的话

标签: javascript reactjs asynchronous promise async-await


【解决方案1】:

使用下面的包装函数 delayed_render(),您可以在 React 组件函数中编写异步代码:

function delayed_render(async_fun, deps=[]) {
    const [output, setOutput] = useState()
    useEffect(async () => setOutput(await async_fun()), deps)
    return (output === undefined) ? null : output
}

此包装器执行延迟渲染:它在初始渲染尝试时返回 null(跳过此特定组件的渲染),然后通过给定的 async_fun() 异步计算(useEffect())正确的渲染输出并调用 re-渲染以将最终结果注入 DOM。这个包装器的使用很简单:

function Component(props) {
    return delayed_render(async () => { /* any rendering code with awaits... */ })
}

例如:

function Component(props) {
    return delayed_render(async () => {
        const resp = await fetch(props.targetURL)     // await here is OK!
        const json = await resp.json()
        return <Child data={json} />
    })
}

更新:添加了 deps 参数。如果您的 async_fun 依赖于 props 或状态变量,则所有这些都必须列在 deps 中以允许重新渲染。请注意,传递deps=null总是重新渲染)在这里不是一个选项,因为output 也是一个状态变量,并且会隐式包含在依赖项中,这会导致无限重新- 在async_fun 调用完成后进行渲染。

此解决方案的灵感来自 Jared Smith 的解决方案,并且是对其的推广。

【讨论】:

  • 感谢这个更新的答案!今天帮助了我。
【解决方案2】:

您应该始终将获取数据等关注点与显示数据等关注点分开。这里有一个父组件,它通过 AJAX 获取数据,然后在数据进来时有条件地渲染一个纯函数式子组件。

class ParentThatFetches extends React.Component {
  constructor () {
    this.state = {};
  }

  componentDidMount () {
    fetch('/some/async/data')
      .then(resp => resp.json())
      .then(data => this.setState({data}));
  }

  render () {
    {this.state.data && (
      <Child data={this.state.data} />
    )}
  }
}

const Child = ({data}) => (
  <tr>
    {data.map((x, i) => (<td key={i}>{x}</td>))}
  </tr>
);

我实际上并没有运行它,所以它们可能是一些小错误,如果你的数据记录有唯一的 id,你应该将它们用于 key 属性而不是数组索引,但你得到了 jist。

更新

同样的事情,但使用钩子更简单、更短:

const ParentThatFetches = () => {
  const [data, updateData] = useState();
  useEffect(() => {
    const getData = async () => {
      const resp = await fetch('some/url');
      const json = await resp.json()
      updateData(json);
    }
    getData();
  }, []);

  return data && <Child data={data} />
}

【讨论】:

  • 谢谢,如果它有效,我会告诉你的。到那时 +1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-14
  • 1970-01-01
  • 2020-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多