Я хочу получить массив из ключей моего объекта, но длина должна быть равна 0, когда объект пуст. Длина массива верна, когда я пытаюсь console.info() с массивом, но мой код зависает, выдавая следующую ошибку в моем браузере, и он останавливает выполнение:
RangeError: invalid array length
burger/transformedIngredients<
src/components/Burger/Burger.js:8
5 | const burger = (props) => {
6 | let transformedIngredients = Object.keys(props.ingredients).map(igKey => (
7 | // eslint-disable-next-line max-len,react/no-array-index-key
> 8 | [...Array(props.ingredients[igKey])].map((_, i) => <BurgerIngredient key = {igKey + i} type = {igKey} />)
9 | )).reduce((arr, el) => (
10 | arr.concat(el)
11 | ), []);
Это код, который я использую:
const burger = (props) => {
let transformedIngredients = Object.keys(props.ingredients).map(igKey => (
// eslint-disable-next-line max-len,react/no-array-index-key
[...Array(props.ingredients[igKey])].map((_, i) => <BurgerIngredient key = {igKey + i} type = {igKey} />)
)).reduce((arr, el) => (
arr.concat(el)
), []);
if (transformedIngredients.length === 0) {
transformedIngredients = <p>Please add some ingredients!</p>;
}
Я прохожу ingredients отсюда:
class BurgerBuilder extends Component {
state = {
ingredients: {
salad: 0,
bacon: 0,
cheese: 0,
meat: 0,
},
totalPrice: 4,
};
render() {
return (
<Fragment>
<Burger ingredients = {this.state.ingredients} />
<BuildControls
ingredientAdded = {this.addIngredientHandler}
ingredientRemoved = {this.removeIngredientHandler}
/>
</Fragment>
);
}



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я действительно не понимаю, почему вы делаете дополнительное сопоставление ключей и создаете многомерный массив, но вы можете изменить свой код на это, если хотите отобразить ингредиент для каждого ключа:
const burger = (props) => {
let transformedIngredients = Object.keys(props.ingredients).map((igKey, i) => (
<BurgerIngredient key = {igKey + i} type = {igKey} />
));
}
Вы вызываете setState где-то внутри своих методов рендеринга?
Нет. Вы можете проверить мой полный код здесь
Судя по скринам, ошибка возникает из-за метода ingredientHandler, но я не могу найти ее в вашем коде.
Извините, возникла проблема с git. Вы можете проверить репо сейчас и найти обновленный код
@shirish хорошо, да, в строке 19 в buildControls вы делаете added = {props.ingredientAdded(ctrl.type)}, который все время вызывает ingredientAdded. Вам нужно изменить его на `add = {() => props.ingredientAdded(ctrl.type)}`. Кстати, имена компонентов React следует начинать с прописных букв.
Я сделал это для removed = {props.ingredientRemoved(ctrl.type)} тоже, и это сработало. Но я до сих пор не понимаю, в чем была ошибка, можете ли вы объяснить это подробнее или указать мне на некоторые документы?
В основном props.ingredientRemoved(ctrl.type) выполняется сразу и вызывает повторную визуализацию, что приводит к ее повторному выполнению и вызывает повторную визуализацию и так далее. Обертывание его в функцию предотвратит то, что, поскольку оно будет вызвано сразу, оно вернет другую функцию, которая будет вызвана позже.
remove = {props.ingredientRemoved(ctrl.type)} это неправильно, если ваш передаваемый параметр, как в этом случае (ctrl.type), вы должны использовать (), например: remove = {() => props.ingredientRemoved(ctrl.type )}
Ошибка может возникнуть, если один из ингредиентов имеет отрицательное значение, например:
state = {
ingredients: {
salad: -1, // this will cause the error
bacon: 0,
cheese: 0,
meat: 0,
},
totalPrice: 4,
};
Вы можете предотвратить эту ситуацию, гарантируя, что отрицательное число не будет передано в конструктор Array, например, вы можете передать 0, если число отрицательное:
[...Array(Math.max(0, props.ingredients[igKey]))]
Ни один из моих ингредиентов не будет иметь отрицательного значения. Там ошибка, о которой был вопрос, решена, но теперь я получаю другую ошибку (проверьте комментарии в первом ответе)
Я прохожу тот же курс и получаю ту же ошибку. Проверьте свой файл reducer.js и сравните его с исходным кодом, предоставленным в курсе. В моем случае массив, переданный из reducer.js, не соответствовал массиву, полученному Burger.js. Ошибка исчезла после исправления файла reducer.js.
Мой код выглядит так после исправления:
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.ADD_INGREDIENT:
return {
...state,
ingredients: {
...state.ingredients,
[action.ingredientName]: state.ingredients[action.ingredientName] + 1
},
totalPrice: state.totalPrice + INGREDIENT_PRICES[action.ingredientName]
};
case actionTypes.REMOVE_INGREDIENT:
return {
...state,
ingredients: {
...state.ingredients,
[action.ingredientName]: state.ingredients[action.ingredientName] - 1
},
totalPrice: state.totalPrice + INGREDIENT_PRICES[action.ingredientName]
};
default:
return state;
}
};
Я учусь реагировать на тот же курс, и у меня была та же проблема, что и у вас. В вашем const INGREDIENT_PRICES все объекты должны иметь тот же регистр, что и в buildcontrols.js, и в этом const элементы управления проверяют верхнюю и нижнюю причину совпадения слов с INGREDIENT_PRICES, после чего проблема будет решена.
в этом случае я сузил свою ошибку до попытки передать значение цены в параметры запроса, установив Number.parseFloat и toFixed для целого числа цен, тем самым устранив ошибку, вызывающую строковое десятичное число.
purchaseContinueHandler = () => {
const queryParams = [];
let price = Number.parseFloat(this.state.totalPrice).toFixed(2);
for (let i in this.state.ingredients) {
queryParams.push(encodeURIComponent(i) + '=' + encodeURIComponent(this.state.ingredients[i]));
}
queryParams.push('price=' + price);
const queryString = queryParams.join('&');
this.props.history.push({
pathname: '/checkout',
search: '?' + queryString
});
ошибка была вызвана для меня наличием десятичной строки в значении цены.
Имеет ту же ошибку, что и у вас, возможно, ошибка была в добавлении ингредиентов.
Решил мою, изменив «[]» на «{}» в строке копирования объекта. Я не заметил, что использовал [].
Я тоже сделал ту же ошибку, заменив буквы "b" и "c" на заглавные. в "беконе" и "сыре".
Сделав каждый символ в одном и том же регистре, проблема решена:
const controls=[
{label:'salad',type:'salad'},
{label:'bacon',type:'bacon'},
{label:'cheese',type:'cheese'},
{label:'meat',type:'meat'}
];
Я следую тому же курсу, пожалуйста, проверьте название ингредиента, которое вы используете в своей базе данных, оно должно быть таким же, как в BuildControls.js, тип ингредиентов должен быть таким же, как вы пишете в своей базе данных. Это определенно решит вашу проблему.
Эта ошибка возникает из-за выбора неправильного имени, поэтому пишет Недопустимая длина массива.
Спасибо всем, кто нашел время, чтобы предоставить свой ответ и мысли. У меня была такая же проблема, и решение состояло в том, чтобы просто изменить значение ключа на нижний регистр,
Например, в приведенном ниже коде:
Ошибка заключалась в том, что 'Price' в верхнем регистре вместо 'price' в нижнем.
checkoutContinuedHandler = () => {
const queryParams = [];
for (let ing in this.state.ingredients) {
queryParams.push(encodeURIComponent(ing) + '=' + encodeURIComponent(this.state.ingredients[ing]));
}
queryParams.push('price=' + this.state.totalPrice.toFixed(2));
const queryString = queryParams.join('&');
this.props.history.push({
pathname: '/checkout',
search: '?' + queryString
});
}Я следовал тому же курсу и столкнулся с той же проблемой. Включено totalPrice как пара ключ-значение в объект ингредиентов (в файле reducer.js), что не так, поскольку это отдельная пара ключ-значение в обновленном состоянии для каждого действия.
Перед исправлением-
import * as actionTypes from './actions';
const initialState = {
ingredients: {
salad: 0,
bacon: 0,
cheese: 0,
meat: 0
},
totalPrice: 4,
};
const INGREDIENT_PRICES = {
salad: 0.5,
bacon: 1.3,
cheese: 0.6,
meat: 1,
};
const reducer = (state = initialState, action) => {
switch(action.type){
case actionTypes.ADD_INGREDIENT: return {
...state,
ingredients: {
...state.ingredients,
[action.ingredientName]: state.ingredients[action.ingredientName] + 1,
`totalPrice: state.totalPrice + INGREDIENT_PRICES[action.ingredientName]`
}
};
case actionTypes.REMOVE_INGREDIENT: return {
...state,
ingredients: {
...state.ingredients,
[action.ingredientName]: state.ingredients[action.ingredientName] - 1,
`totalPrice: state.totalPrice - INGREDIENT_PRICES[action.ingredientName]`
}
}
default : return state;
}
};
export default reducer;
После исправления-
import * as actionTypes from './actions';
const initialState = {
ingredients: {
salad: 0,
bacon: 0,
cheese: 0,
meat: 0
},
totalPrice: 4,
};
const INGREDIENT_PRICES = {
salad: 0.5,
bacon: 1.3,
cheese: 0.6,
meat: 1,
};
const reducer = (state = initialState, action) => {
switch(action.type){
case actionTypes.ADD_INGREDIENT: return {
...state,
ingredients: {
...state.ingredients,
[action.ingredientName]: state.ingredients[action.ingredientName] + 1,
},
`totalPrice: state.totalPrice + INGREDIENT_PRICES[action.ingredientName]`
};
case actionTypes.REMOVE_INGREDIENT: return {
...state,
ingredients: {
...state.ingredients,
[action.ingredientName]: state.ingredients[action.ingredientName] - 1,
},
`totalPrice: state.totalPrice - INGREDIENT_PRICES[action.ingredientName]`
}
default : return state;
}
};
export default reducer;
Просто удалите оператор спреда из ...state.ingredients, и все заработает!
На самом деле, я новичок в React и проходил курс. После копирования вашего кода ошибка исчезла, но мой браузер выдал другую ошибку:
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.Есть ли решение этой проблемы?