Возникли проблемы с рендерингом объекта в реквизите - PullRequest
0 голосов
/ 20 сентября 2019

Привет, ребята , это мой первый пост о переполнении стека, но я сделаю все возможное, чтобы придерживаться правильных форматов!Подводя итог, я потратил последние пять часов на этот компонент реагирования, пытаясь отрисовать список объектов, передаваемых из состояния моего родительского компонента, через реквизиты ребенка.Я перепробовал все пути, исследовал несколько решений, но, похоже, ничего не получалось.Это мой первый раз, когда я использую веб-пакет, может быть, есть какой-то плагин, который я должен загрузить для использования React State и реквизитов?Я не знаю.В любом случае, я опубликую фрагменты ниже и опишу каждый шаг в меру своих возможностей.

Приложение для моих родителей

У меня не было проблем с этим, я регистрировал свои результаты каждый шагтаким образом, для факта я знаю, что функция getWeather правильно выбирает данные из API Weatherbit и устанавливает состояние, которое, в свою очередь, как вы увидите, передает массив вchild через его реквизит.

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 и отображает данные дочернего элемента.

ведение журнала дочернего компонентаподробности

Сведения о дочерних компонентах

Ладно, последняя вещь ... Я также публикую инструмент Dev Chrome, который показывает, какие компоненты имеют реквизиты и состояния.На этом изображении видно, что дочерний компонент сделал получил нужные реквизиты и соответственно обновил свое состояние. Но, опять же, по какой-то причине он не позволяет мне получить к ним доступ и отобразить результаты

детали реакции дочернего компонента

Я действительно извиняюсь, если этовопрос слишком длинный ... И да, я понимаю, что несколько похожих постов уже решены, но я просмотрел большинство из них, и моя ситуация просто не относится к тому, что я могу сказать ... Я не эксперт, но я не новичок, чтобы реагировать.Это действительно поставило меня в тупик. Заранее большое спасибо за помощь .Я могу предоставить дополнительные скриншоты, фрагменты кода или даже видео, если это поможет !!!

makezi

EDIT

Я добавил замену блока кода функцией карты,и, как вы видите, проблема не в том, как я доставляю данные в 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>
        }
    }

улучшенные подробности регистрации

Второе редактирование комментария Минь Хонга Трона

Я обновил функцию getWeather моего родителя, чтобы она стала асинхронной, а также отредактировал ведение журнала, чтобы оно было более наглядным.Вы можете видеть , хотя массив 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>
        }
    }

улучшенные подробности регистрации

Повторяю, в моем компоненте будет получена функцияprops: "console.log ('nextProps.weatherArray)" ДЕЛАЕТиспустить полный массив данных ... ОДНАКО, "console.log ('this.state.currentWeather)" не делает.Даже после запуска setState.Но затем, когда я использую React Chrome Dev Tools, вы можете видеть, что DID состояния передается в дочерний компонент.Мой метод рендеринга просто не может прочитать данные по какой-то причине ..


THIRD EDIT

Этот первый фрагмент моего родительского компонента.Вы можете видеть, что он передает 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.Вместо того, чтобы пытаться отобразить данные в состоянии моего ребенка, теперь я просто пытаюсь использовать данные реквизита, которые были переданы из родительского компонента ребенка.К сожалению, я все еще сталкиваюсь с той же проблемой.Функция рендеринга моего ребенка читает массив реквизитов как пустой и поэтому не может отображать данные.Я не могу убрать оператор 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>
        }
    }


}

до запуска снимка экрана функции getWeather

после запуска снимка экрана функции getWeather

Посмотрите на два приведенных выше снимка экрана.Первый - до того, как я запустил свою функцию извлечения, поэтому инструменты разработки React Chrome показывают, что массив props моего ребенка пуст (конечно).НО на следующем снимке экрана показано, что, хотя инструменты React Dev показывают, что реквизиты моего дочернего компонента имеют полный массив, мой метод рендеринга по-прежнему считывает длину массива реквизитов как 0 ....

Ответы [ 3 ]

0 голосов
/ 20 сентября 2019

Вам не нужно использовать componentWillReceiveProps.Это добавляет много ненужной сложности для вас.Когда состояние изменяется в родительском компоненте, он автоматически перерисовывает свои дочерние элементы.Пропустите componentWillReceiveProps и выполните рендеринг в дочернем компоненте, используя this.props.weatherArray.

0 голосов
/ 20 сентября 2019

Документация React предлагает избегать устаревших жизненных циклов, таких как componentWillReceiveProps.

Распространенным заблуждением является то, что getDerivedStateFromProps и componentWillReceiveProps вызываются только тогда, когда реквизиты «изменяются».Эти жизненные циклы вызываются каждый раз, когда родительский компонент перезапускается, независимо от того, отличаются ли реквизиты от ранее.Из-за этого всегда было небезопасно безоговорочно переопределять состояние, используя любой из этих жизненных циклов.Это приведет к потере обновлений состояния.

Документация гласит:

componentDidMount () вызывается сразу после монтирования компонента ... Если вам нужно загрузитьданные из удаленной конечной точки, это хорошее место для создания сетевого запроса.

РЕДАКТИРОВАТЬ: Глядя на третье редактирование, я предполагаю, что вы выбирали вызовыв течение жизненного цикла componentDidMount, так как вы продолжали повторять, что выборка «работает».

Поскольку приведенные выше фрагменты на самом деле не показывают метод componentDidMount, я предлагаю попробовать переместить всю логику выборки в соответствующий метод componentDidMount, а затем установить состояние оттуда.

0 голосов
/ 20 сентября 2019

Во-первых, функция 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 .

Пожалуйста, измените ваш код, если он не работаетПожалуйста, зарегистрируйте данные nextProps и состояние дочернего компонента в componentWillReceiveProps и покажите мне скриншот.

Извините, мой английский очень плохой.

...