Входное значение не обновляется после изменения setState... Увеличение и уменьшение

У меня есть эти кнопки увеличения и уменьшения, которые добавляют или вычитают. Я импортирую значения по умолчанию из реквизита, а затем хочу разрешить пользователю вносить коррективы. Поэтому, когда я обновляю состояние (серию) для соответствующей группы, кажется, что оно обновляется просто отлично ... но входное значение остается «14» в HTML, хотя я установил его на value = {this.state[mppt_number].series}. Разве он не должен автоматически обновляться при изменении состояния?

Вероятно, это связано с переменной [mppt_number].... если mppt_number = 1 при создании элемента, не будет ли значение value = {this.state[1].series} и value = {this.state[2].series} при втором создании? Я не знаю... Я немного новичок в этом.

import React from 'react';
//import { defaultValues } from './Calculator';


//Will be passed in as props just have it here for now to ease testing. This can range from 1 to N
const defaultValues = {
    1:{
        array_isc: 10.88,
        array_power: 3834.5999999999995,
        array_vmp: 497,
        array_voc: 584.3312579999999,
        series: 14,
        string: 1,
    },


2: {array_isc: 9.00,
    array_power: 3834.5999999999995,
    array_vmp: 600,
    array_voc: 584.3312579999999,
    series: 12,
    string: 1},
}

const mppt = 2


class Tool extends React.Component{
    constructor(props){
        super(props)

        this.state = {
            stringSizingElement : null, 
        }
        this.handleStringChange =this.handleStringChange.bind(this)
        this.stringSizingElementHelper = this.stringSizingElementHelper.bind(this)

    }

    componentDidMount() {
        let s = {};
        for (let i = 1; i <= mppt; i++) {
          s[`${i}`] = defaultValues[i];
        }
    
        this.setState((prevState) => ({ ...s }), () => {
            console.info(this.state);
            this.createStringSizingElementDefaults()
        });
      }


      //Create this element mppt_number of times for each MPPT
    stringSizingElementHelper( mppt_number){
        let stringSizing = (   
            <div className='container' id  = {mppt_number} key = {mppt_number}>
                <div className = "row justify-content-center">
                <label>MPPT {mppt_number}</label>
                    </div>
                <div className = "row justify-content-center" id= {`${mppt_number}`}>
                    <div className = "col-4">
                    <label className='container'>Series</label>
                        <div className = {`input-group container ${`${mppt_number}`}`} >
                            
                            <button className ='btn btn-primary decrement' onClick = {this.handleSeriesChange} >-</button>
                            <input className = "form-control series" min = "0" name = "quantity" value = {this.state[mppt_number].series} type = "number" disabled/>
                            <button className ='btn btn-primary increment' onClick = {this.handleSeriesChange} >+</button>
                        </div>
                    </div>
            </div>
            <br/>
            <br/>
        </div>    
        );

        return stringSizing;
    }


    createStringSizingElementDefaults(){
        let temp = []
        //Creating element for each mppt (1:{} , 2: {}) of times for each MPPT This number ranges. 
        for (let i=1 ; i <= mppt ; i++) {
          const  result = this.stringSizingElementHelper(i)
            temp.push(result)
    
        }

        this.setState({stringSizingElement: temp})
    }
    
 
    handleSeriesChange(e){
        if (e.target.classList.contains('decrement')){
            //Get ID to Figure out which MPPT Is being changed
            const mppt_number = e.target.parentNode.parentNode.parentNode.parentNode.id
            var newValues = {...this.state[mppt_number]}
            newValues.series = this.state[mppt_number].series - 1
            this.setState({[mppt_number] : newValues}, ()=>{
                console.info(this.state[mppt_number].series)
            });

        }else if (e.target.classList.contains('increment')){
            const mppt_number = 
           e.target.parentNode.parentNode.parentNode.parentNode.id
            var newValues = {...this.state[mppt_number]}
            newValues.series = this.state[mppt_number].series + 1
            console.info(newValues.series)
            this.setState({[mppt_number] : newValues}, ()=>{
                console.info(this.state[mppt_number].series)
            })

        }else{
            console.info('Error??')
        }
    }


    render(){

        return(
            <div className = "temp container">
                <div className = "form-row  justify-content-center">
                    <label htmlFor = "sel2"><h4>String Sizing Tool:</h4> 
                    </label>
                </div>
                {this.state.stringSizingElement}
                <br/>
                <br/>
                {undefined}
                <br/>
                <br/>
            </div>
        )
    }
}

Помочь этой девушке? :D

ОБНОВЛЯТЬ:

Больше не хранил этот массив JSX в состоянии. Я создаю их между рендерингом и возвратом сейчас. Теперь это не «рендеринг», когда он хранится в состоянии? Я все еще получаю те же результаты. :(

Теперь функция возвращает массив вместо установки состояния.

createStringSizingElementDefaults(){
        let temp = []
        //Creating element for each mppt (1:{} , 2: {}) of times for each MPPT This number ranges. 
        for (let i=1 ; i <= mppt ; i++) {
          const  result = this.stringSizingElementHelper(i)
            temp.push(result)
    
        }

        return temp

    }

Этот массив теперь создается между рендерингом и возвратом.

render(){
 let stringSizingElement = this.createStringSizingElementDefaults()

 

    return(
        <div className = "temp container">
            <div className = "form-row  justify-content-center">
                <label htmlFor = "sel2"><h4>String Sizing Tool:</h4></label>
            </div>
            {stringSizingElement}
            <br/>
            <br/>
            {undefined}
            <br/>
            <br/>
        </div>
    )
}

КОД РЕШЕНИЯ ПОСЛЕ ПОМОЩИ:

import React from 'react';
//import { defaultValues } from './Calculator';
//import './xxxxx.css';

//Will be passed in as props just have it here for now to ease testing
const defaultValues = {
   
     1: {array_isc: 10.88,
        array_power: 3834.5999999999995,
        array_vmp: 497,
        array_voc: 584.3312579999999,
        series: 14,
        string: 1,
    },

    2: {array_isc: 9.00,
        array_power: 3834.5999999999995,
        array_vmp: 600,
        array_voc: 584.3312579999999,
        series: 12,
        string: 1},

    3: {array_isc: 1.00,
            array_power: 3834.5999999999995,
            array_vmp: 600,
            array_voc: 584.3312579999999,
            series: 12,
            string: 1},
}




class Tool extends React.Component{
    constructor(props){
        super(props)

        this.state = {
            
        }
        this.handleStringChange =this.handleStringChange.bind(this)
        this.handleSeriesChange =this.handleSeriesChange.bind(this)
      

    }

    componentDidMount() { 
        let s = {};
        Object.keys(defaultValues).map((mppt_number, i) => (
            s[`${mppt_number}`] = defaultValues[mppt_number]
        ))
    
        this.setState((prevState) => ({ ...s }), () => {
            console.info(this.state);
           
        });
      }





    handleSeriesChange(e){
        if (e.target.classList.contains('decrement')){
            //Get ID to Figure out which MPPT Is being changed

            console.info(e.target.parentNode.parentNode.parentNode.parentNode.id)
            const mppt_number = e.target.parentNode.parentNode.parentNode.parentNode.id
            var newValues = {...this.state[mppt_number]}
            newValues.series = this.state[mppt_number].series - 1
            this.setState({[mppt_number] : newValues}, ()=>{
                console.info(this.state[mppt_number].series)
            })
            


        }else if (e.target.classList.contains('increment')){
            console.info(e.target.parentNode.parentNode.parentNode.parentNode.id)
            const mppt_number = e.target.parentNode.parentNode.parentNode.parentNode.id
            var newValues = {...this.state[mppt_number]}
            newValues.series = this.state[mppt_number].series + 1
            this.setState({[mppt_number] : newValues}, ()=>{
                console.info(this.state[mppt_number].series)
            })

        }else{
            console.info('Error?? Maybe remove this')
        }

    }


    render(){

     

        return(
            <div className = "temp container">
                <div className = "form-row  justify-content-center">
                    <label htmlFor = "sel2"><h4>String Sizing Tool:</h4></label>
                </div>
                
                {Object.keys(this.state).map((mppt_number, i) => (
                    <div className='container' id  = {mppt_number} key = {mppt_number}>
                            <div className = "row justify-content-center">
                            <label>MPPT {mppt_number}</label>
                                </div>
                            <div className = "row justify-content-center" id= {`${mppt_number}`}>
                                <div className = "col-4">
                                <label className='container'>Series</label>
                                    <div className = {`input-group container ${`${mppt_number}`}`} >
                                        
                                        <button className ='btn btn-primary decrement' onClick = {this.handleSeriesChange} >-</button>
                                        <input className = "form-control series" min = "0" name = "quantity" value = {this.state[mppt_number].series} type = "number" disabled/>
                                        <button className ='btn btn-primary increment' onClick = {this.handleSeriesChange} >+</button>
                                    </div>
                                </div> 
                            </div>
                        <br/>
                        <br/>
                    </div> 
))}
                <br/>
                <br/>
                {undefined}
                <br/>
                <br/>
            </div>
        )
    }
}
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
812
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

setStste перезаписывает только старое состояние в новом состоянии, поэтому:

            this.setState({[mppt_number] : newValues}, ()=>{
                console.info(this.state[mppt_number].series)
            })

не будет обновлять [mppt_number] : newValues, но заменяет состояние на {[mppt_number] : newValues}. Если вы хотите:

            this.setState((oldState) => ({...oldState, ...{[mppt_number] : newValues}}), ()=>{
                console.info(this.state[mppt_number].series)
            })

выше будет работать. Предоставление объекта в качестве первого параметра setState не приводит к обновлению, как вы предполагали. Предоставление функции вместо объекта, работающего, как указано выше.

Если вы новичок в React, а не для немедленного использования job, я рекомендую использовать функциональные компоненты и хуки вместо метода класса. Это просто и делает внешний вид кода таким хорошим. Попробуй это!

Добавлять: Проблема возникает здесь:

        this.setState({stringSizingElement: temp})

temp содержит узлы React и отображается в исходном состоянии. tringSizingElement в state всегда отображаются узлы, поэтому переменные фиксируются как постоянные значения.

Чтобы этого избежать, перестаньте хранить узлы в state. Узлы в state НЕ являются областью рендеринга React DOM, это означает, что они не обновляют свои переменные.

    createStringSizingElementDefaults(){
        let temp = []
        for (let i=1 ; i <= mppt ; i++) {
          const  result = this.stringSizingElementHelper(i)
            temp.push(result)
    
        }

        return temp
    }

Чтобы сделать узлы createStringSizingElementDefaults напрямую, этой проблемы не возникнет.

Добавить 2:

this это неприятная проблема. Какие this баллы должны отличаться от того, что вы думаете. Если вызов this.func.bind(this), this в func фиксируется. Другими словами, this.state никогда не меняется. Так что, даже если звонить his.createStringSizingElementDefaults() снова и снова, результаты одинаковы! Чтобы избежать обеих проблем? Один из ответов - это снова звонок bind. Но это не рекомендуется по причине производительности. Другой простой. Не получать доступ к состоянию в функциях-членах. Если вы хотите, укажите его в качестве параметров.

И для этого вам поможет «пусть представление зависит только от состояния». Решение сделать просмотр только из состояния не смущает. Что это означает, следующий пример:

class Example extends React.Component{
    constructor(props){
        super(props)

        this.state = {
            somelist: [1, 2, 3],
        }
        this.handleAppend = this.handleAppend.bind(this)
        this.handleRemove = this.handleRemove.bind(this)
    }
    handleAppend(){
        this.setState({someList} => {
            let s = [...someList]
            s.push(spmeList[someList.length - 1])
            return {someList: s}
        })
    }
    handleRemove(){
        this.setState({someList} => {
            let s = [...someList]
            s.pop()
            return {someList: s}
        })
    }
    render(){
        return(
            <div>
                <button onClick = {this.handleAppend}>Append</button>
                <button onClick = {this.handleRemove}>Remove</button>
                {this.state.someList.map(v => <div>{v}</div>)}
            </div>
        )
    }
}

Вы можете подтвердить, что представление определяется только состоянием. Для изменения состояния требуется нажать кнопку и запустить setState через событие onClick. Данные передаются в одну сторону. Это важно.

Подведем итог,

  • setState принимает функцию обновления
  • Не включать узлы в состояние
  • Не получать доступ к this.state в функциях участников
    • Если хотите, укажите его в качестве параметров
  • Сохраняйте поток данных односторонним

Если у вас есть особые обстоятельства, я не прекращаю использовать компоненты в стиле классов, но нет, я настоятельно рекомендую стиль функциональных компонентов.

Я получил те же результаты, что и в прошлый раз. console.info показывает, что он обновлен в обеих версиях, моей старой версии и вашей версии, но элемент ввода остается value='14'. Значение элемента html не обновляется. Не отражает новое состояние.

monochromaticmau 19.12.2020 05:13

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

Akihito KIRISAKI 19.12.2020 05:34

Привет, я больше не храню массив JSX в состоянии и запускаю createStringSizingElementDefaults в рендере. Я обновил свой исходный пост, чтобы уточнить. Я думаю, что вы предложили не хранить его в состоянии? Но я получаю ту же проблему. Если я сделал то, что вы предложили, неправильно, можете ли вы привести пример того, что, по вашему мнению, я должен сделать, чтобы исправить это?

monochromaticmau 19.12.2020 16:57

Извините, что я должен сказать было так не хватает. Скоро перепишу код.

Akihito KIRISAKI 19.12.2020 17:03

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

monochromaticmau 19.12.2020 20:15

Другие вопросы по теме