const pick = (items) => {
const filteredItems = items.filter(item => item.count > 0);
const total = filteredItems.reduce((acc, item) => acc + item.count, 0);
if (total === 0) {
return null;
}
const pickedChance = Math.random();
let storedChance = 0;
for (const item of filteredItems) {
storedChance += item.count / total;
if (pickedChance < storedChance) {
item.count -= 1;
return item.name;
}
}
}
pick(items);
React.StrictMode
отсутствует.App
подписываетесь на изменения store
и обновляете состояние им.src/style.css
, а надо бы для каждого компонента их разделять. Я бы разбивал на модули..jsx
используйте только для компонентов. У Вас есть файлы с логикой, которые имеют такое расширение.sirch-panel.jsx
(а еще лучше бы SearchPanel.jsx
) лучше хранить состоянием только значение поля для новой сущности.store.dispatch
. Диспатчинг событий можно перенести в тот же connect (можно даже bindActionCreators использовать).switch
. Для удаления можете воспользоваться методом массива .filter
. Для пометки important можете воспользоваться методом массива .map
. И вообще его вынести в отдельную директорию, т. к. он не является компонентом (как и action creators).className={important ? "important list-item" : "list-item"}
можете воспользоваться classnames или clsx.id: idCounter
можно будет заменить на Date.now()
. const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
const expression = /[-–—]/g;
while (walker.nextNode()) {
const node = walker.currentNode;
if (expression.test(node.textContent)) {
node.textContent = node.textContent.replace(expression, '-');
}
}
String, Boolean, Object, Array
. При вызове классов Number, String, Boolean
без оператора new
они постараются привести переданное значение к примитиву (например String(true) // "true"
. В том случае, если их вызвать с оператором new
, то они вернут новый объект (не путать с Object), значением в котором будет переданное значение. Лучше так не создавать переменные данных классов, а использовать примитивы (об этом можете почитать в книге Стоян Стефанов - JavaScript Шаблоны). У Object
особое поведение при его вызове без new
- он постарается понять тип переменной и впоследствии вернет экземпляр класса определенного примитива:Object(100) // Number { 100 }
typeof Object(100) // "object"
typeof 100 // "number"
Object(100) instanceof Number // true
100 instanceof Number // false
Array
без ключевого слова new
или с ним:function drawImage(callback) {
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
if (currentImg.src) {
console.log(1);
img.src = currentImg.src;
} else {
console.log(2);
img.src = currentImage.src;
}
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
ctx.filter = canvasFilter;
ctx.drawImage(img, 0, 0);
callback();
};
}
download.addEventListener('click', function(e) {
drawImage(function () {
console.log(canvas.toDataURL());
const dataURL = canvas.toDataURL("image/jpeg");
let link = document.createElement('a');
link.download = 'download.png';
link.href = dataURL;
link.click();
});
});
function drawImage(callback) {
return new Promise(function (resolve) {
const img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
if (currentImg.src) {
console.log(1);
img.src = currentImg.src;
} else {
console.log(2);
img.src = currentImage.src;
}
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext("2d");
ctx.filter = canvasFilter;
ctx.drawImage(img, 0, 0);
resolve();
};
});
}
download.addEventListener('click', function(e) {
drawImage().then(function () {
console.log(canvas.toDataURL());
const dataURL = canvas.toDataURL("image/jpeg");
let link = document.createElement('a');
link.download = 'download.png';
link.href = dataURL;
link.click();
});
});
// или
download.addEventListener('click', async function(e) {
await drawImage();
console.log(canvas.toDataURL());
const dataURL = canvas.toDataURL("image/jpeg");
let link = document.createElement('a');
link.download = 'download.png';
link.href = dataURL;
link.click();
});
export const ModalBlock: React.FC<ModalBlockProps> = ({
title,
onClose,
isOpen = false,
children,
}: ModalBlockProps): React.ReactElement | null => {
const [closing, setClosing] = useState(false);
const handleClose = () => setClosing(true);
useEffect(() => {
if (isOpen) {
setClosing(false);
}
}, [isOpen]);
if (!isOpen) {
return null;
}
return (
<Dialog TransitionComponent={Transition} open={!closing && isOpen} onExited={onClose} aria-labelledby='form-dialog-title'>
<DialogTitle id='form-dialog-title'>
<IconButton onClick={handleClose} color='secondary' aria-label='close'>
<CloseIcon style={{ fontSize: 26 }} color='secondary' />
</IconButton>
{title}
</DialogTitle>
<DialogContent>{children}</DialogContent>
</Dialog>
);
};
Math.round(((b ** 2) - 4 * a * c) ** 1/2);
а ((b ** 2) - 4 * a * c) ** (1 / 2);
.if (b => 1, c => 1) {
b = "+ " + b
c = "+ " + c
}
let stringifiedB = b >= 0 ? `+ ${b}` : `- ${Math.abs(b)}`;
let stringifiedC = c >= 0 ? `+ ${c}` : `- ${Math.abs(c)}`;
console.log(`${a}х² ${stringifiedB}x ${stringifiedC} = 0`);
if (false, true) {
console.log(1);
} else {
console.log(2);
}
// 1
if (false, true, false) {
console.log(1);
} else {
console.log(2);
}
// 2
if
-блок. - if $(this).hasClass("catalog-button_active") {
+ if ($(this).hasClass("catalog-button_active")) {
class Example {
constructor() {}
}
const entries = [
new Example(),
{},
new Object(),
[],
new Array(),
42,
'Hello World',
true,
null,
undefined
];
entries.forEach((entry, index) => {
if (entry instanceof Example) {
console.log(`is example - ${index}`);
} else if (entry instanceof Array) {
console.log(`is array - ${index}`);
} else if (entry instanceof Object) {
console.log(`is object - ${index}`);
} else {
console.log(`is ${typeof entry} - ${index}`)
}
});
/*
is example - 0
is object - 1
is object - 2
is array - 3
is array - 4
is number - 5
is string - 6
is boolean - 7
is object - 8
is undefined - 9
*/
const ThemedInput = withStyles((theme) => ({
root: {
"&:hover": {
"&$underline": {
"&::before": {
borderColor: theme.palette.primary.dark
}
}
}
},
input: {
fontWeight: 700,
color: theme.palette.primary.main
},
underline: {
"&::before": {
borderColor: theme.palette.primary.main
}
}
}))(Input);
const ThemedSelect = withStyles((theme) => ({
select: {
"&:hover": {
"& ~ $icon": {
color: theme.palette.primary.dark
}
}
},
icon: {}
}))(Select);
<ThemedSelect input={<ThemedInput />}></ThemedSelect>
let numbers = [1, 2, 3, 0, 4, 5, 6];
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] > 0) {
sum += numbers[i];
} else {
break;
}
}
console.log(sum);
<=
. Как только проитерируется весь массив - цикл не будет завершен, а при попытке достать элемент (а мы уже всё проитерировали) Вы рискуете получить NaN
.i < 0
. Тут сразу две ошибки: не i
а b[i]
; и не <
, а ===
. Если оставить меньше нуля, то даже при достижении элемента равному нулю цикл не будет остановлен. - let val = document.querySelector('#changer').value;
+ let val = document.querySelector('#changer');
let el = document.createElement('h3');
let cont = document.querySelector('#box');
t.addEventListener('input', () => {
el.textContent = t.value;
});
el.textContent = t.value;
cont.append(el);
index.html
. Следующий шаг - History API, это пригодится для подмены URL и генерации Ваших ссылок. А для того чтобы загрузить необходимое содержимое необходимо будет проанализировать location.pathname
и отобразить необходимую информацию (как будто Вы нажали на элемент меню).location.hash
для хранения уникального URL, загружать будете также как в первом варианте. useEffect(() => {
let intervalId = setInterval(async () => {
const response = await fetch('http://127.0.0.1:8000/api/timecalculate', {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
credentials: 'include',
});
const content = await response.json();
const now = new Date();
console.log(content + now);
}, 10000)
return () => {
clearInterval(intervalId);
};
}, []);