数据准备好后如何渲染组件?

IT技术 javascript reactjs promise
2021-05-17 06:36:03

我想弄清楚如何在数据准备好时填充/渲染组件?本质上,我有一个脚本来查询我的服务器并返回数据,然后我解析它并将其放入一个包含我需要的属性的集合中。然后在另一个文件中,我有正在寻找该对象的 react 组件,但它们同时运行,因此当组件正在寻找它时,该对象不存在。

我不知道如何继续。

这是我的组件:

let SliderTabs = React.createClass({
    getInitialState: function() {
        return { items: [] }
    },
    render: function() {
        let listItems = this.props.items.map(function(item) {
            return (
                <li key={item.title}>
                    <a href="#panel1">{item.title}</a>
                </li>
            );
        });

    return (
            <div className="something">
                <h3>Some content</h3>
                    <ul>
                        {listItems}
                    </ul>
            </div>
        );
    }
});

ReactDOM.render(<SliderTabs items={home.data.slider} />,                
    document.getElementById('slider-tabs'));

我如何获取我的数据:

var home = home || {};

home = {
  data: {
    slider: [],
    nav: []
  },
  get: function() {

    var getListPromises = [];

    $.each(home.lists, function(index, list) {
      getListPromises[index] = $().SPServices.SPGetListItemsJson({
        listName: home.lists[index].name,
        CAMLViewFields: home.lists[index].view,
        mappingOverrides: home.lists[index].mapping
      })
      getListPromises[index].list = home.lists[index].name;
    })

    $.when.apply($, getListPromises).done(function() {
      home.notice('Retrieved items')
      home.process(getListPromises);
    })
  },
  process: function(promiseArr) {
    var dfd = jQuery.Deferred();

    $.map(promiseArr, function(promise) {
      promise.then(function() {
        var data = this.data;
        var list = promise.list;

        // IF navigation ELSE slider
        if (list != home.lists[0].name) {
          $.map(data, function(item) {
            home.data.nav.push({
              title: item.title,
              section: item.section,
              tab: item.tab,
              url: item.url.split(",")[0],
              path: item.path.split("#")[1].split("_")[0]
            })
          })
        } else {
          $.map(data, function(item) {
            home.data.slider.push({
              title: item.title,
              url: item.url.split(",")[0],
              path: item.path.split("#")[1]
            })
          })
        }
      })
    })

    console.log(JSON.stringify(home.data))
    dfd.resolve();
    return dfd.promise();
  }
}

$(function() {
  home.get()
})
4个回答

在 React 中执行此操作的一种常见方法是跟踪获取数据的时间。这可以通过例如isFetching在您的州拥有一个字段来完成

// This would be your default state
this.state = {
  isFetching: false
};

然后,当您触发请求(最好在 componentDidMount 中)时,您isFetching使用以下方法设置为 true:

this.setState({ isFetching: true });

最后,当数据到达时,您再次将其设置为 false:

this.setState({ isFetching: false });

现在,在您的渲染函数中,您可以执行以下操作:

render () {
 return (
    <div className="something">
      <h3>Some content</h3>
      {this.state.isFetching ? <LoadingComponent /> : (
         <ul>
           {listItems}
         </ul>
      )}
    </div> 
  )
}

通过使用状态,您不必担心告诉您的组件做某事,而是它对状态的变化做出react并相应地呈现它。

更新:

如果您打算实际使用 React,我建议您将您的方法更改为我上面描述的方法(在React 文档中阅读更多内容)。也就是说,将get函数中的代码移动到 React 组件的componentDidMount函数中。如果那不可能,你可以等着打电话

ReactDOM.render(
  <SliderTabs items={home.data.slider} />,                
  document.getElementById('slider-tabs')
);

直到您的数据到达。

这里是 React 做这些事情的方式的解释,tl;dr - 立即渲染组件并显示加载指示器直到数据准备好或nullrender方法返回

将加载的数据放在父组件中,在加载数据时更新组件的 props。

使用默认props而不是默认状态,因为您在示例中根本没有使用状态。将“getInitialState”替换为:

   getDefaultProps: function() {
     return {
       items: []
     };
   }

您应该测试数据收集的长度。如果集合为空,则返回一个占位符(例如一个加载轮)。在其他情况下,您可以照常显示数据集合。

const SliderTabs = ({items}) => {
    let listItems = <p>Loading data...</p>

    if(items.length != 0) 
        listItems = items.map(item => 
            <li key={item.title}>
                <a href="#panel1">{item.title}</a>
            </li>
        )

    return (
        <div className="something">
            <h3>Some content</h3>
                <ul>
                    {listItems}
                </ul>
        </div>
    )
}

ReactDOM.render(
    <SliderTabs items={home.data.slider} />,                
    document.getElementById('slider-tabs')
)

我使用函数式方式来定义 React 组件,因为这是推荐的方式,而您不需要状态、引用或生命周期方法。

如果你想在 ES6 类或 React.createCompnent 中使用它(应该避免),只需将该函数用作渲染函数。(不要忘记items从props中提取


编辑:通过阅读新答案,我意识到我还没有完全回答。

如果您希望在加载数据时更新视图,您必须集成更多的数据获取代码。React 中的一个基本模式是将组件分为两种类型:容器组件和展示组件。

容器只会处理逻辑并获取有用的数据。另一方面,展示组件将只显示容器提供的数据。

这里有一个小例子:(在 jsfidle 上试试)

测试实用程序

var items = [{title: "cats"},{title: "dogs"}]

//Test function faking a REST call by returning a Promise.
const fakeRest = () => new Promise((resolve, reject) =>
  setTimeout(() => resolve(items), 2000)
)

容器组件

//The Container Component that will only fetch the data you want and then pass it to the more generic Presentational Component
class SliderTabList extends React.Component {
  constructor(props) { //
    super(props)
    //You should always give an initial state (if you use one of course)
    this.state = { items : [] }
  }

  componentDidMount() {
    fakeRest().then(
      items => this.setState({ items }) //Update the state. This will make react rerender the UI.
    )
  }

  render() {
    //Better to handle the fact that the data is fetching here.
    //This let the Presentational Component more generic and reusable
    const {items} = this.state
    return (
      items.length == 0 
        ? <p>Loading Data...</p>
        : <List items={items} />
    )
  }
}

展示组件

//The Presenational Component. It's called List because, in fact, you can reuse this component with other Container Component. Here is power of React.
const List = ({items}) => {
    //Prepare the rendering of all items
    const listItems = items.map(item => 
      <li key={item.title}>
        <a href="#panel1">{item.title}</a>
      </li>
    )

    //Simply render the list.
    return (
      <div className="something">
        <h3>Some content</h3>
          <ul>
            {listItems}
          </ul>
      </div>
    )
}

渲染应用程序

//Mount the Container Component. It doesn't need any props while he is handling his state itself
ReactDOM.render(
    <SliderTabList />,                
    document.getElementById('slider-tabs')
)

除了检查长度是否不为 0,您还可以在状态中初始化itemsnull,以便能够区分获取数据和空数据。操作系统放置标志(状态中的布尔值fetchingData)以了解数据是否正在获取的另一种常见方法但是,在许多文章中,通常建议尽可能少地使用状态,然后从中计算出您需要的所有内容。所以在这里,我建议您检查长度或null.