【问题标题】:I get an infinite loop only when I render a child component - ReactJs仅当我渲染子组件时才会出现无限循环 - ReactJs
【发布时间】:2019-01-26 04:18:38
【问题描述】:

好吧,这让我快疯了!不得不从头开始重新编码项目以查明问题所在。

基本上,我正在尝试通过构建一个可以分享 Spotify 歌曲的网络应用程序来练习 React。所以这是我的组件树(只有重要的组件:App.js -> [Navbar, Posts] -> 然后在 Posts 里面我有一个 Post 组件列表。这里是代码:

import React, { Component } from 'react';
import './App.css';
import {BrowserRouter} from 'react-router-dom';
import Navbar from './components/Navigation/Navbar';
import Posts from './containers/Posts/Posts';


class App extends Component {
  render() {
    return (
      <BrowserRouter>
        <div className="App">
          <Navbar />
          <Posts />
        </div>
      </BrowserRouter>
    );
  }
}

export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

import React, { Component } from 'react';
import Post from './Post/Post';
import $ from 'jquery';

class Posts extends Component {
    state = {
        posts: null,
        // addingNewPost: false
    }

    componentDidMount() {
        $.ajax({
            url: 'https://music-blog-app.firebaseio.com/users/user/posts.json',
            success: (response) => {
                //console.log(response); // object of objects
                // converting to array of objects
                const responseArray = Object.keys(response).map(i => response[i]);
                //console.log(responseArray);
                this.setState({
                    posts: responseArray
                })
                // console.log(this.state.posts);
            }
            //error
        });
    }

    // addingNewPostHandler = () => {
    //     this.setState({addingNewPost: true});
    // }

    // cancelNewPostHandler = () => {
    //     this.setState({addingNewPost: false});
    // }

    sharedNewPostHandler = (caption, embedSrcLink) => {

        var newPostToAdd = {
            caption: caption,
            embedSrcLink: embedSrcLink
        }

        var postsToUpdate = this.state.posts.slice();
        postsToUpdate.push(newPostToAdd);

        // $.ajax({
        //     type: 'POST',
        //     url: 'https://music-blog-app.firebaseio.com/users/user/posts.json',
        //     success: (response) => {
        //         console.log(response);
        //         this.setState(prevState =>({
        //             addingNewPost: false,
        //             posts: [...this.state.posts, newPostToAdd]
        //         })); 
        //     } 
        //     // error
        // });
    }

    render() {

        var postsToRender = <p>Nothing here</p>

        console.log(this.state.posts);
        if(this.state.posts) {
            var myPosts = this.state.posts.slice();
        }
        console.log(myPosts);
 
        let render;
        if(myPosts) {
            render = (myPosts.map((post, index) => { return <p>IF I REPLACE THIS BY RENDERING POST component, I get an infinite loop</p>}))
        } else {
            render = <p>still waiting...</p>
        }

        return (
            <div className="container posts-container">
                {/* <p>jsdhfjhd</p>
                {myPosts ? (myPosts.map((post, index) => {
                    // console.log(post)
                    return <Post key={post} caption={this.state.posts[index].caption} embedSrcLink={this.state.posts[index].embedSrcLink} />
                })) : <p>still waiting...</p>} */}
                {render}
            </div>
        ); 
    }
}

export default Posts;

import React, { Component } from 'react';
import './Post.css';
import PosterProfile from '../../../components/PosterProfile/PosterProfile';

const post = (props) => (
    <div className="post">
        <PosterProfile />
        <div className="card" style={{width: '18rem'}}>
            <div className="card-body">
                <h5 className="card-caption">{props.caption}</h5>
                <div className="embed-iframe">
                    <iframe title="embed" src={props.embedSrcLink} width="300" height="380" frameBorder="0" allowtransparency="true" allow="encrypted-media"></iframe>
                </div>
            </div>
            <div className="card-footer">
                <a href="#like" className="card-link link">Like</a>
                <a href="#comment" className="card-link link">Comment</a>
                <a href="#repost" className="card-link link">Repost</a>
            </div>
        </div>
    </div>
)

export default post;

问题来了!!所以Posts的render方法里面的这段代码:

render = (myPosts.map((post, index) => { return <p>IF I REPLACE THIS BY RENDERING POST component, I get an infinite loop</p>}))

我将其替换为

render = (myPosts.map((post, index) => { 

return <Post key={post} caption={this.state.posts[index].caption} embedSrcLink={this.state.posts[index].embedSrcLink}
}))

顺便说一下,我正在从 firebase 数据库中获取帖子。 请帮忙 !提前谢谢你:)

【问题讨论】:

  • 您可以先从Post 组件中删除&lt;PosterProfile /&gt; 组件以消除这种可能性(因为我们在您的帖子中没有看到该组件的代码,这可能成为罪魁祸首)
  • 问题可能是您正在导出post 而不是Post
  • @jmancherje PosterProfile 只是一个带有图像的 div。但是我删除了它仍然无法正常工作
  • @AdrianAvram 不是这样
  • @AdrianAvram 虽然用大写字母命名组件是一种常见的做法,但他的变量是post,他正在导出post,所以导出很好。而导入,import Post from './Post/Post' 实际上是一个别名,所以他可以随意命名它

标签: javascript ajax reactjs render infinite-loop


【解决方案1】:

在 react 中渲染列表/数组需要您为每个项目添加一个键。从文档: Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity https://reactjs.org/docs/lists-and-keys.html#keys

我相信您的 sn-ps 中发生的事情是您将键分配为对象而不是字符串。这肯定会导致意外的行为或错误。

【讨论】:

  • 好的,谢谢。最初我打算按照您的建议使用 key={post.embedSrcLink} 但我认为如果我的数据库中有两次相同的歌曲(具有相同的 src 链接)可能会导致麻烦。所以现在它是索引。但我会在每篇文章中添加和 id。
猜你喜欢
  • 2019-01-07
  • 2016-02-29
  • 2017-03-16
  • 2019-05-27
  • 2010-12-24
  • 2021-12-06
  • 2021-01-16
  • 2018-07-20
  • 1970-01-01
相关资源
最近更新 更多