麻烦渲染道具中传递的对象

时间:2019-09-20 02:58:19

标签: javascript reactjs components state

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

我的父母应用

在这一点上,我没有遇到任何麻烦,我已经记录了结果的每一步,因此对于事实,我知道 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详细信息

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

child component react details

如果这个问题太冗长,我真的道歉...是的,我知道已经解决了多个类似的帖子,但是我查看了其中的大多数帖子,但是我的情况并不适用我的情况...我不是专家,但我不是新手。这真让我难过。 非常感谢您的帮助。如果有帮助,我可以提供其他屏幕截图,代码段甚至视频!

makezi

编辑

我添加了用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

MinhHưngTrầ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

需要重申的是,在我的组件中,receiveprops函数是:“ console.log('nextProps.weatherArray)”会发出完整的数据数组...但是,“ console.log('this.state.currentWeather” )“ 才不是。即使在setState运行之后。但是,当我使用React Chrome Dev Tools时,您可以看到脸上的状态DID传递给了子组件。我的渲染方法由于某种原因无法读取数据。


第三编辑

第一个片段是我的父组件。您会看到它正在将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之后,我将发布孩子的代码段。现在,我不再尝试显示处于孩子状态的数据,而只是尝试使用从孩子的父组件传递来的道具数据。不幸的是,我仍然遇到同样的问题。我孩子的render函数正在读取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

查看上面的两个屏幕截图。第一个是在我运行提取功能之前,因此React Chrome Dev Tools显示我孩子的props数组为空(当然)。但是之后的屏幕截图显示,即使React React Tools显示我的子组件的props具有完整的数组,我的render方法仍然读取该prop数组的长度为0。...

3 个答案:

答案 0 :(得分:0)

首先,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组件的状态,并向我显示其屏幕截图。

对不起,我的英语不好。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

反应文档建议避免使用遗留生命周期,例如componentWillReceiveProps。

  

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

文档说:

  

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

编辑: 查看第三次编辑,我一直假设您是通过componentDidMount生命周期来获取呼叫,因为您一直在迭代获取“作品”的过程。

由于上述代码段实际上并未显示componentDidMount方法,因此建议尝试将所有提取逻辑移至相应的componentDidMount方法,然后从那里设置状态。