【问题标题】:Having Trouble Rendering an Object Passed Down in Props在渲染道具中传递的对象时遇到问题
【发布时间】:2020-01-21 02:09:13
【问题描述】:

大家好, 这是我在 Stack Overflow 上的第一篇文章,但我会尽力遵守正确的格式!总而言之,我在这个 react 组件上花费了最后五个小时,试图通过子组件的 props 呈现从父组件的状态向下传递的对象列表。我已经尝试了所有方法,研究了多种解决方案,但似乎没有任何效果。这是我第一次使用 webpack,也许我必须下载一些插件才能使用 React 状态和道具?我不知道。无论如何,我将在下面发布 sn-ps,并尽我所能描述每个步骤。

我的家长应用

这方面我没有遇到任何问题,我已经记录了每一步的结果,所以我知道 事实 getWeather 函数正在正确获取数据来自 Weatherbit API 并设置状态,正如您将看到的那样,它又通过它的 props 将数组传递给子节点。

class App extends React.Component {

constructor(props) {
    super(props);
    this.state = {weatherArray: []}
    this.getWeather = this.getWeather.bind(this);
}


getWeather() {
    const newWeather = WeatherHelper.inputPrompt();
    console.log(newWeather)
    this.setState({weatherArray: newWeather})
    WeatherHelper.showData()

}

仍在我的父母应用中

如您所见,我将状态作为道具传递给孩子,它会在 setState 运行时立即更新

<div id='side-apps'>
    <div id='weather-side-app'>
        <WeatherApp weatherArray={this.state.weatherArray} />
    </div>
</div>

我的孩子应用

所以这就是奇怪的地方...... 这是我的子组件,正如您所看到的,当组件收到新的道具时,它首先检查这些道具是否已更新。然后,假设这些道具是新的,componentWillReceiveProps 方法将设置状态并相应地重新渲染(或者你会这么想)。您还可以看到我已经广泛使用日志记录来尝试记录我的问题,接下来我将提供一个屏幕截图。请注意,在 componentWillReceiveProps 方法中,如果道具与原始道具不同(即更新),该方法将在更新的道具周围记录多个破折号,以便您可以指出它们(您会看到)。顺便说一句,我知道我什至不应该使用 componentWillReceiveProps 方法,单独的父 setState 函数应该足以更新我的组件,但可惜没有(我尝试的其他 10 种不同的方法也没有)。

class WeatherApp extends React.Component {

constructor(props) {
    super(props);
    this.state = {currentWeather: []}
}

handleCloseClick() {
    WeatherHelper.hideData();
}


componentWillReceiveProps(nextProps) {
    if (nextProps.weatherArray !== this.state.currentWeather) {
        console.log('---')
        console.log(nextProps.weatherArray)
        console.log('---')
        this.setState({currentWeather: nextProps.weatherArray})
    } else {
        {console.log("if you see an array under this comment," +
            "that means the above if statement read the state's 
             currentWeather array's length" +
            " as zero. EVEN THOUGH the componentWillReceiveProps method" +
            " updated and set the state accordingly...")}
        console.log(nextProps.weatherArray)
        console.log(this.state.currentWeather)
    }
}



render() {

    if (this.state.currentWeather.length > 0) {
        return (
        <div class='weatherApp-main'>
            <div className='close-sidebar-button'>
                <img src='https://i.postimg.cc/hj0rYKxc/close-button.png' onClick={this.handleCloseClick}/>
            </div>
            <div id='weather-app-header'>
            <h2>{this.state.currentWeather}</h2>
                <h3></h3>
                <h4></h4>
            </div>
            <div id='weather-app-table'>
            </div>
        </div>
        )
    } else {
        {console.log(this.state.currentWeather)}
        return <p></p>
        }
    }


}

子组件日志记录详细信息

如果您查看屏幕截图,您可以看到我从我孩子的 componentWillReceiveProps 方法中记录的日志证明 setState 函数必须已被调用,但出于某种原因它不会更新孩子的 html 和显示数据。

child component logging details

子组件反应细节

好的,最后一件事...我还发布了 react chrome 开发工具,它向您展示了哪些组件具有道具和状态。您可以在这张图片中看到,子组件确实收到了预期的道具并相应地更新了它的状态。 但同样,由于某种原因,它不允许我访问它们并显示结果

child component react details

如果这个问题太长,我真的很抱歉......是的,我知道已经解决了多个类似的帖子,但我已经查看了其中的大部分,我的情况并不适用于我所知道的......我不是专家,但我不是反应的新手。这真的难倒我。 非常感谢您的帮助。如果有帮助,我可以提供额外的屏幕截图、代码 sn-ps 甚至视频!!!

制作子

编辑

我添加了用 map 函数替换代码块,如您所见,问题不在于我如何将数据传递到 DOM。问题是由于某种原因,我的组件没有读取其状态的数据(我将发布更详细的屏幕截图以更好地记录问题)

render() {
    console.log('++++')
    console.log(this.state.currentWeather.length);

    if (this.state.currentWeather.length > 0) {
        return (
        <div class='weatherApp-main'>
            <div className='close-sidebar-button'>
                <img src='https://i.postimg.cc/hj0rYKxc/close-button.png' onClick={this.handleCloseClick}/>
            </div>
            <div id='weather-app-header'>
            {this.state.currentWeather.map(item => <div><span>{item.city}</span></div>)}
                <h3></h3>
                <h4></h4>
            </div>
            <div id='weather-app-table'>
            </div>
        </div>
        )
    } else {
        {console.log("if you see an array under this comment," +
            "that means the above if statement read the state's currentWeather array's length" +
            " as zero. EVEN THOUGH the componentWillReceiveProps method" +
            " updated and set the state accordingly...")}
        {console.log(this.state.currentWeather)}
        return <p></p>
        }
    }

better logging details

Minh Hưng Trần 评论的第二次编辑

我将我父母的 getWeather 函数更新为异步,还编辑了日志以更具描述性。您可以看到 即使 state 中的 currentWeather 数组有 8 个对象,长度仍被读取为零!我认为问题不在于比较数组。出于某种原因,我的渲染函数无法读取我的状态中的数据......或者运行 setState 时它没有被更新。 **您无法从屏幕截图中看出,但 nextProps 数组已被读取并完全记录到控制台。虽然在运行 setState 之后,''console.log(this.state.currentWeather)'' 记录了一个空数组,很奇怪吧? **

componentWillReceiveProps(nextProps) {
    if (nextProps.weatherArray !== this.state.currentWeather) {
        console.log("--nextProps weatherArray--")
        console.log(nextProps.weatherArray)
        console.log('--------------------------')
        this.setState({currentWeather: nextProps.weatherArray})
        console.log("==child's state==")
        console.log(this.state.currentWeather)
        console.log("=================")
    } else {
        console.log(nextProps.weatherArray)
        console.log(this.state.currentWeather)
    }
}



render() {
    console.log("++child's state's length in render method++")
    console.log(this.state.currentWeather.length);
    console.log("+++++++++++++++++++++++++++++++++++++++++++")

    if (this.state.currentWeather.length > 0) {
        return (
        <div class='weatherApp-main'>
            <div className='close-sidebar-button'>
                <img src='https://i.postimg.cc/hj0rYKxc/close-button.png' onClick={this.handleCloseClick}/>
            </div>
            <div id='weather-app-header'>
            {this.state.currentWeather.map(item => <div><span>{item.city}</span></div>)}
                <h3></h3>
                <h4></h4>
            </div>
            <div id='weather-app-table'>
            </div>
        </div>
        )
    } else {
        {console.log("if you see an array under this comment," +
            "that means the above if statement read the state's currentWeather array's length" +
            " as zero. EVEN THOUGH the componentWillReceiveProps method" +
            " updated and set the state accordingly...")}
        {console.log(this.state.currentWeather)}
        return <p></p>
        }
    }

better logging details

重申一下,在我的 componentwillreceiveprops 函数中:“console.log('nextProps.weatherArray)”确实会发出完整的数据数组......但是,“console.log('this.state.currentWeather )“ 才不是。即使在 setState 运行之后。但是当我使用 React Chrome 开发工具时,你可以看到 face 中的状态 DID 被传递给了子组件。我的渲染方法由于某种原因无法读取数据..


第三次编辑

第一个 sn-p 是我的父组件。您可以看到它正在将 weatherArray 传递给孩子的道具。顺便说一下,这个 getWeather 函数确实有效,我一直在通过日志记录来验证它。问题出在我孩子的头上,我很确定。

class App extends React.Component {

constructor(props) {
    super(props);
    this.state = {weatherArray: []}
    this.getWeather = this.getWeather.bind(this);
}


async getWeather() {
    const newWeather = await WeatherHelper.inputPrompt();
    console.log(newWeather)
    this.setState({weatherArray: newWeather})
    WeatherHelper.showData()

}

render() {

    return (
        <div>
            <div id='main'>
                <div id='introduction'>
                    <Intro />
                </div>
                <div id='attachment'>
                    <Attachment getWeather={this.getWeather} />
                </div>
                <div id='body'>
                    <div id='about'>
                        <About />
                    </div>
                <div id='personal-info-skills'>
                    <div id='info'>
                        <p id='info-header'>personal information</p>
                        <Info />
                    </div>
                    <div id='pskills'>
                        <p id='pskills-header'>personal skills</p>
                        <PSkills />
                    </div>
                </div>
                <div className='divider'>
                <p></p>
                </div>
                <div id='professions-languages'>
                    <div id='professions'>
                        <p id='professions-header'>professions</p>
                        <Professions />
                    </div>
                    <div id='languages'>
                        <p id='languages-header'>languages</p>
                        <Languages />
                    </div>
                </div>
                </div>
            </div>
            <div id='side-apps'>
                <div id='weather-side-app'>
                    <WeatherApp weatherArray={this.state.weatherArray} />
                </div>
            </div>
        </div>
        )
}

}

现在我将在注释掉 componentWillReceiveProps 后发布我孩子的代码 sn-p。现在我只是尝试使用从孩子的父组件传递的道具数据,而不是尝试以我孩子的状态显示数据。不幸的是,我仍然遇到同样的问题。我孩子的渲染函数将 props 数组读取为空,因此无法显示数据。我不能在 render 方法的开头删除 if 语句,因为我的代码在尝试读取空数组的属性时会抛出错误

render() {

    if (this.props.weatherArray.length > 0) {
        return (
        <div class='weatherApp-main'>
            <div className='close-sidebar-button'>
                <img src='https://i.postimg.cc/hj0rYKxc/close-button.png' onClick={this.handleCloseClick}/>
            </div>
            <div id='weather-app-header'>
            {this.props.weatherArray.map(item => <div><span>{item.city}</span></div>)}
                <h3></h3>
                <h4></h4>
            </div>
            <div id='weather-app-table'>
            </div>
        </div>
        )
    } else {
        {console.log("if you see an array under this comment," +
            "that means the above if statement read the state's currentWeather array's length" +
            " as zero. EVEN THOUGH the React Chrome Dev Tools shows that" +
            " the child has a full currentWeather array in props...")}
        {console.log(this.state.currentWeather)}
        return <p></p>
        }
    }


}

before running getWeather function screen shot

after running getWeather function screen shot

看上面两张截图。第一个是在我运行我的 fetch 函数之前,所以 React Chrome 开发工具显示我孩子的 props 数组是空的(当然)。但是之后的屏幕截图显示,即使 React 开发工具显示我的子组件的道具有一个完整的数组,我的渲染方法仍然将该道具数组的长度读取为 0....

【问题讨论】:

  • 我不确定您为什么要尝试在 h2 标记中显示 currentWeather,因为 currentWeather 是一个包含对象的数组 - 这应该会引发错误。我建议用.map循环它,即this.state.currentWeather.map(item =>
    {item.city}...
    )
  • 我试过了,我现在就做给你看。对不起,我应该恢复正常。感谢您的回复!
  • 如果你在编辑完一段代码后查看屏幕截图,我对其进行了更改,因此它也显示了 react 组件的 props & state。它清楚地表明 currentWeather 数组中充满了数据......我无法弄清楚为什么我的渲染方法没有获取该数据。 如果有人想查看完整代码,我可以添加一个指向 git-hub 存储库的链接,请问!
  • 请告诉我们您在哪里调用 getWeather。
  • setState 是一种异步方法,因此您的 console.log 仍可能打印空数组。您可以通过执行setState({currentWeather: nextProps.weatherArray}, () =&gt; console.log(this.state)) 来测试这一点,这将在完成setState 后将console.log 函数作为回调运行。此外,是否有任何特定情况为什么您的子组件必须保持与父组件相同数组的状态?我敢打赌componentWillReceiveProps 是这里的问题,因为它是一个同步函数(在处理异步获取时会收到不匹配的渲染,因此自 React 16.3 起它就被弃用了)

标签: javascript reactjs components state


【解决方案1】:

React 文档建议避免遗留生命周期,例如 componentWillReceiveProps。

一个常见的误解是 getDerivedStateFromProps 和 componentWillReceiveProps 仅在道具“更改”时才被调用。每当父组件重新渲染时,都会调用这些生命周期,无论 props 是否与之前“不同”。正因为如此,使用这些生命周期中的任何一个来无条件地覆盖状态总是不安全的。这样做会导致状态更新丢失。

文档说:

componentDidMount() 在组件安装后立即调用...如果您需要从远程端点加载数据,这是实例化网络请求的好地方。

编辑: 查看第三次编辑,我一直假设您正在通过 componentDidMount 生命周期获取调用,因为您一直在迭代获取“有效”。

由于上面的 sn-ps 实际上并没有显示 componentDidMount 方法,我建议尝试将所有获取逻辑移动到适当的 componentDidMount 方法,然后从那里设置状态。

【讨论】:

  • 嗨,Abe,感谢您的意见。我会试一试。不幸的是,问题不再是传递正确的道具并相应地更新状态。如果您查看我的帖子的第三次编辑,您会看到我删除了 componentWillReceiveProps 方法和子组件的状态,并保持简单,其中我的父组件将 prop 传递给子组件,并且子组件将其作为 props 访问。但这仍然不起作用,如果您查看我第三次编辑中的屏幕截图,React Chrome 开发工具显示道具已正确传递给孩子..(继续...)
  • ..... 但由于某种原因,我的孩子无法在渲染语句中访问或阅读它们。可能是因为我的子组件渲染后道具正在更新?这让我大吃一惊,我一生都无法弄清楚为什么我的子组件无法读取它的道具。
  • 嘿Abe,所以componentWillMount 只在第一次渲染组件时被调用,对吗?所以就我而言,我只需要更新组件后的数据。我尝试使用必要的反应生命周期方法,但没有任何效果。我的子组件的渲染方法无法读取它的道具。我要疯了
  • 嘿伙计们,还有其他人有什么想法吗?我仍然无法弄清楚这一点。如果有帮助,我可以在 github 上发布完整的代码。谢谢!
  • 是的,这可能会有所帮助,我会尝试在我的机器上重现它
【解决方案2】:

您不需要使用 componentWillReceiveProps。这为您增加了许多不必要的复杂性。当父组件中的状态发生变化时,它会自动重新渲染其子组件。省略 componentWillReceiveProps 并使用 this.props.weatherArray 在子组件中渲染。

【讨论】:

  • 嗨,克雷格,感谢您的回复。我明白,我之前提到过同样的事情。就像你说的,我只是回到了我的状态。我让我的父组件将 weatherArray 作为道具传递给孩子,并注释掉了 componentWillReceiveProps。但是,在我的渲染方法中,检查道具 weatherArray 是否为空的 if 语句仍然提出了空...
  • 再一次,当我使用 React Chrome 开发工具时,它显示我孩子的道具已满是数据数组。只是由于某种原因,我的渲染方法无法读取道具或状态...
  • 嘿克雷格看看我的第三次编辑,你会看到我想要传达的内容。由于某种原因,我的子组件的渲染方法无法读取我孩子的道具。这两个屏幕截图和代码 sn-ps 应该可以很好地描述我的意思。希望能澄清我的问题...非常感谢!
  • 嘿伙计们,还有其他人有什么想法吗?我仍然无法弄清楚这一点。如果有帮助,我可以在 github 上发布完整的代码。谢谢!
【解决方案3】:

首先,getWeather 函数正在获取 Weatherbit API,因此您必须使用 await
关于获取功能。在你上面的代码中,我认为你使用函数WeatherHelper.inputPrompt() 来获取数据,所以函数将是:

async getWeather() {
    const newWeather = await WeatherHelper.inputPrompt();
    console.log(newWeather)
    this.setState({weatherArray: newWeather})
    WeatherHelper.showData()
}

在您上面的代码中,console.log 是打印数据,因为它可以异步打印数据(根据我的经验)。

其次,你不应该用 !== 比较数组和数组,阅读this

请更改您的代码,如果不能正常工作,请在 componentWillReceiveProps 中记录下 nextProps 的数据和 Child 组件的状态,并显示它的屏幕截图。

对不起,我的英语很糟糕。

【讨论】:

  • 刚刚更新了日志。重申一下,在我的 componentwillreceiveprops 函数中:“console.log('nextProps.weatherArray)”确实会发出完整的数据数组......但是,“console.log('this.state.currentWeather)”不会。即使在 setState 运行之后。但是当我使用 React Chrome 开发工具时,你可以看到 face 中的状态 DID 被传递给了子组件。我的渲染方法由于某种原因无法读取数据..
  • 我想看nextProps的日志(不是nextProps.weatherArray)
  • Hey Minh,对不起,我最终摆脱了 componentWillReceiveProps。我现在没有尝试显示来自我的子组件状态的数据,而是尝试在子组件的 props 中显示数据,从它的父组件传递下来。如果您查看我的第三次编辑,您会发现即使 React Chrome 开发工具显示我的子组件的 props 已满是数据,但我的子组件的渲染方法无法读取它...
  • 你可以在 setState 之后尝试this.forceUpdate() in parent: this.setState({ weatherArray: newWeather }, () =&gt; this.forceUpdate());
  • 当 WeatherHelper.showData() 被调用时会发生什么?
猜你喜欢
  • 1970-01-01
  • 2011-06-28
  • 2021-12-27
  • 2020-09-07
  • 1970-01-01
  • 2012-03-28
  • 2018-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多