如何在react渲染功能中异步等待?

IT技术 javascript reactjs asynchronous promise async-await
2021-02-05 16:23:42

我非常熟悉async await但后端nodejs但是我遇到了一个场景,我必须在前端使用它。

我得到了对象数组,在这些对象中我得到lat lng了这些地方。现在使用react-geocode我可以获得单个的地名,lat lng但我想在 map 函数中使用它来获取地名。所以正如我们所知,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 函数时,它不会返回任何内容。任何人都可以帮助我哪里出错了吗?

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,你应该将它们用于键属性而不是数组索引,但你得到了 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
2021-04-09 16:23:42

使用下面的包装函数delay_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在初始渲染尝试时返回(跳过这个特定组件的渲染),然后通过给定异步计算(useEffect())正确的渲染输出async_fun()并调用重新渲染以将最终结果注入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 或 state 变量,则必须将所有这些都列出deps以允许重新渲染。请注意,传递deps=null始终重新渲染)在这里不是一个选项,因为它output也是一个状态变量,并且会隐式包含在依赖项中,这将导致async_fun调用完成后无限重新渲染

该解决方案的灵感来自于 Jared Smith 的解决方案,并且是对其的概括。

感谢您提供此更新的答案!今天帮了我。
2021-03-22 16:23:42