У меня есть эти кнопки увеличения и уменьшения, которые добавляют или вычитают. Я импортирую значения по умолчанию из реквизита, а затем хочу разрешить пользователю вносить коррективы. Поэтому, когда я обновляю состояние (серию) для соответствующей группы, кажется, что оно обновляется просто отлично ... но входное значение остается «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>
)
}
}





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 в функциях участников
Если у вас есть особые обстоятельства, я не прекращаю использовать компоненты в стиле классов, но нет, я настоятельно рекомендую стиль функциональных компонентов.
Я упустил понимание фундаментальной проблемы. Я прочитаю код еще раз, минутку, пожалуйста... Но то, что я сказал, должно помочь вам понять.
Привет, я больше не храню массив JSX в состоянии и запускаю createStringSizingElementDefaults в рендере. Я обновил свой исходный пост, чтобы уточнить. Я думаю, что вы предложили не хранить его в состоянии? Но я получаю ту же проблему. Если я сделал то, что вы предложили, неправильно, можете ли вы привести пример того, что, по вашему мнению, я должен сделать, чтобы исправить это?
Извините, что я должен сказать было так не хватает. Скоро перепишу код.
Мне нужно будет посмотреть, что означают компоненты стиля класса и стиль функционального компонента. Это сработало!!! Я обновлю новый код. Это также намного чище!
Я получил те же результаты, что и в прошлый раз. console.info показывает, что он обновлен в обеих версиях, моей старой версии и вашей версии, но элемент ввода остается value='14'. Значение элемента html не обновляется. Не отражает новое состояние.