Как забрать значение с активной кнопки?
Ребята, подскажите по Реакту. Функциональный компонент отрисовывает 3 импута (type=range) + 4 кнопки (одна из 4 кнопок активна, массив isActive) + компонент total (собирает значения со всех импутов и кнопок, согласно формуле = (height + weight - age) * ratio). Вопрос: Как правильно написать переменную ratio, чтобы она забирала значение "ratio" активной кнопки из массива isActive?
export default function Component() {
const [ranges, setRanges] = useState([
{
id: 'height',
min: 50,
max: 220,
label: 'height (sm)',
lng: 'lng-height',
value: 135,
},
{
id: 'weight',
min: 1,
max: 200,
label: 'weight (kg)',
lng: 'lng-weight',
value: 100,
},
{ id: 'age', min: 1, max: 110, label: 'age', lng: 'lng-age', value: 55 },
]);
const [isActive, setActive] = useState([
{ id: 'a0', status: true, name: 'low', ratio: 1.2 },
{ id: 'a1', status: false, name: 'small', ratio: 1.375 },
{ id: 'a2', status: false, name: 'medium', ratio: 1.55 },
{ id: 'a3', status: false, name: 'high', ratio: 1.725 },
]);
const chooseRange = (id, value) => {
setRanges(
ranges.map((item) => (item.id === id ? { ...item, value } : item))
);
};
const chooseActive = (id) => {
setActive(
isActive.map((item) =>
item.id === id ? { ...item, status: true } : { ...item, status: false }
)
);
};
const height = ranges[0].value;
const weight = ranges[1].value;
const age = ranges[2].value;
let ratio = ????;
const total = (height + weight - age) * ratio;
return (
<section id='component'>
<div className='line line2'>
<div className='ranges df'>
{ranges.map((item) => (
<RangeInput
key={item.id}
onChange={chooseRange}
value={item.value}
{...item}
/>
))}
</div>
</div>
<div className='line line3'>
<div className='btns df fww'>
{isActive.map((item) => (
<Btn
key={item.id}
onClick={() => chooseActive(item.id)}
ratio={item.ratio}
className={
item.status
? `btn lng-${item.name} active`
: `btn lng-${item.name}`
}>
{item.name}
</Btn>
))}
</div>
</div>
</div>
<div className='line'>
<Total
title={'Result'}
subtitle={'Rate:'}
total={total}
/>
</div>
</section>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Ответы (1 шт):
Если вкратце то значение нужно вытягивать из стейта isActive по статусу. Я создал дополнительную функцию calcTotal которая и занимается расчетами.
По-хорошему в React никаких вычислений не должно болтаться между функциями.
В стейте желательно держать только то что меняется в процессе работы компонента, либо приходит через API запросы.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Add React in One Minute</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin ></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin ></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
<!-- Load our React component. -->
<script type="text/babel">
window.useState = React.useState;
window.useEffect = React.useEffect
const RangeInput =({id, onChange })=>
<input onChange={(event) => onChange(id, Math.floor(event.target.value * 100)/100 )} type="range"/>
const Btn =({ratio, id, onChange, checked, children})=><label>
<input type="radio" onChange={()=>onChange(id)} value={ratio} name="ratio" checked={checked}/>{children}
</label>
const Total =({title,subtitle,total})=>(
<div>
<p>title={'Result'}</p>
<p>subtitle={'Rate:'}</p>
<p>total={total}</p>
</div>
)
function Component() {
const [total, setTotal] = useState(0)
const [ranges, setRanges] = useState([
{
id: 'height',
min: 50,
max: 220,
label: 'height (sm)',
lng: 'lng-height',
value: 135,
},
{
id: 'weight',
min: 1,
max: 200,
label: 'weight (kg)',
lng: 'lng-weight',
value: 100,
},
{ id: 'age', min: 1, max: 110, label: 'age', lng: 'lng-age', value: 55 },
]);
const [isActive, setActive] = useState([
{ id: 'a0', status: true, name: 'low', ratio: 1.2 },
{ id: 'a1', status: false, name: 'small', ratio: 1.375 },
{ id: 'a2', status: false, name: 'medium', ratio: 1.55 },
{ id: 'a3', status: false, name: 'high', ratio: 1.725 },
]);
useEffect(()=>{
const ratio = isActive.find(e => e.status === true).ratio;
console.log(ratio)
const height = ranges[0].value;
const weight = ranges[1].value;
const age = ranges[2].value;
setTotal((height + weight - age) * ratio);
}, [isActive, ranges ])
const chooseRange = (id, value) => {
setRanges(
ranges.map((item) => (item.id === id ? { ...item, value } : item))
);
};
const chooseActive = (id) => {
setActive(
isActive.map((item) =>
item.id === id ? { ...item, status: true } : { ...item, status: false }
)
);
};
return (
<section id='component'>
<div className='line line2'>
<div className='ranges df'>
{ranges.map((item) => (
<RangeInput
key={item.id}
onChange={chooseRange}
value={item.value}
{...item}
/>
))}
</div>
</div>
<div className='line line3'>
<div className='btns df fww'>
{isActive.map((item) => (
<Btn
key={item.id}
onChange={chooseActive}
id={item.id}
ratio={item.ratio}
checked={item.status ? "checked": ""}
className={
item.status
? `btn lng-${item.name} active`
: `btn lng-${item.name}`
}>
{item.name}
</Btn>
))}
</div>
</div>
{/*</div>*/}
<div className='line'>
<Total
title={'Result'}
subtitle={'Rate:'}
total={total}
/>
</div>
</section>
);
}
const App = () => {
return (
<div>
<Component/>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
</script>
</body>
</html>