【问题标题】:Populating a render method using a separate method in ReactJS在 ReactJS 中使用单独的方法填充渲染方法
【发布时间】:2020-02-11 16:08:37
【问题描述】:

好的,所以每个人都知道单独的映射将完成在 React 渲染方法中渲染组件的技巧,如下所示:

var listOfService = ['A', 'B', 'C', 'D', 'E'];
const listItems = listOfService.map((singleItem) =>
    <a className="style_class">{singleItem}</a>
);

如果您在渲染方法的返回中调用 listItems,您将获得列表,这就是单个列表,但我有一个 firebase firestore 数据库,我想遍历该数据库并将每个文档打印为我调用了一个 React 组件 Service,我知道你不能在循环或 if 语句中使用 JSX,所以我尝试了这个:

renderServices() {
    let db = firebase.firestore();
    var details = [[]];
    db.collection('providers').get().then(function (snapshot) {

            snapshot.forEach(function (doc) {

                details.push(
                    [
                        doc.data().owner_name,
                        doc.data().experience,
                        doc.data().charges,
                        doc.data().address,
                        doc.data().home_service,
                        doc.data().highlights,
                        doc.data().certifications,
                        doc.data().specialty,
                        doc.data().facility
                    ]
                );
                //tried loading here Serivce, didn't work
            });
        })
        .catch(function (error) {
            console.log(error);
        });
    details.map((singleDetail) =>
        (< Service details={singleDetail} />)
    );

}

所以我尝试了这个但它不起作用,我写了一些控制台日志并且数据正确输入。首先,我得到“providers”文档的整个数组,提供者列表作为“snapshot”传递,所以我用另一个函数循环快照,该函数正在获取一个名为doc的文档,然后推送它在var 中称为details,这是一个数组但是!它不起作用,即使数据在那里也没有填充数组,因此我无法映射,关于如何解决这个问题的任何想法?

【问题讨论】:

  • “我知道你不能在循环或 if 语句中使用 JSX”是什么意思?您已经从循环内部返回 JSX,所以您确定这就是您的意思吗?
  • 我对 Firestore 没有太多经验,但通常像这样的操作是异步的(基于您对 then 的使用,我会说是这种情况)。当您偶然尝试执行map 时,details 仍然是一个空数组吗?
  • @BrianThompson 是的,详细信息数组保持为空,这很奇怪。我在 details.push() 之前写了 console.log 行,它显示了每个数据,但它似乎无法将相同的数据传递给细节数组。它就像某种阻塞和超出范围的问题
  • 创建 jsx 元素数组,即:代码中的服务组件。将 doc 作为详细信息传递给服务并从函数返回详细信息数组。

标签: javascript reactjs firebase google-cloud-firestore


【解决方案1】:

您需要将数据的加载和数据的渲染分开,因为检索数据是asynchronous,而渲染需要是synchronous

例如,在您的情况下,您将详细信息推送到 then 回调中的数组中 - 这将在您的主函数中发生 async,因此当您调用 details.map 时它仍然是空的(回调没有t 触发填充它)。

相反,您可以加载数据并将其存储在状态中,然后在可用时进行渲染。我个人更喜欢async/await,但同样的逻辑可以通过在promises上使用then来实现:

const [details, setDetails] = useState([]);

// Load the data on initial load or setup the effect to fire when reload is needed
useEffect(() => {

  // Async function that loads the data and sets the state once ready
  const loadData = async () => {
    const details = [];
    try {
      const snapshot = await db.collection('providers').get();
      snapshot.forEach((doc) => {
        details.push([
          // your details stuff
        ]);
      }
    } catch (ex) {
      // Handle any loading exceptions
    }

    setDetails(details);
  }
}, [])


// Render the available details, you could also add conditional rendering to check
// if the details are available or not yet
return (
  <div>
    {details.map((singleDetail) => (
      <Service details={singleDetail} />
    )};
  </div>
);

如果您使用 React 类而不是函数式组件,您可以从 componentDidMount 调用加载,并在加载后仍然设置状态,然后在渲染时映射状态数据。

【讨论】:

  • 好的,我做了类似的事情,它似乎将所有数据加载到数组中,但它不像你在代码中写的那样映射,让我看看这是怎么回事
【解决方案2】:

我找到了解决方案,使用 ReactDOM.render 方法

先做一个全局数组:

var Services = [];

然后添加一个可以放置和渲染数组的DOM元素:

<div className="row d-flex justify-content-center" id='service-div'>

</div>

一旦你有 DOM 元素,让页面加载,当加载完成时,ComponentDidMount() 被调用,所以把你的方法放在那里

ComponentDidMount(){
this.renderServices();}

现在在这个方法中,只需填充数组,然后使用 ReactDOM.render 方法将其渲染到给定的 DOM 元素

async renderServices() {

    let history = this.props.history; //in case the method can't access the history

    let db = firebase.firestore();
    selectedServices = this.props.location.state.selectedServices;

    var database = firebase.database();

    db.collection('providers').where('services', 'array-contains-any',
        selectedServices).get()
        .then(function (snapshot) {
            let idCount = 0;
            snapshot.forEach(function (doc) {

                let tempDetails = [];
                tempDetails.push(
                    doc.data().owner_name,
                    doc.data().experience,
                    doc.data().charges,
                    doc.data().address,
                    doc.data().home_service,
                    doc.data().highlights,
                    doc.data().certifications,
                    doc.data().specialty,
                    doc.data().facility,
                    doc.data().services,
                    doc.data().call_extension,
                    idCount.toString()
                );

                Services.push(<Service details={tempDetails} history={history} />); //adding the Service Component into a list
                idCount++;
            });
            ReactDOM.render(<div>{Services}</div>, document.getElementById('service-div')); //now rendering the entire list into the div
        }).catch(function (error) {
            console.log(error);

        });



}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-16
    • 1970-01-01
    • 2020-11-11
    相关资源
    最近更新 更多