Я ищу способ вычисления значений состояния, которые зависят от других значений состояния, с помощью React Hooks.
Я знакомлюсь с React Hooks. До сих пор я использовал useState и useEffect. Я знаю о других хуках, например useReduce, useCallback и т. д.
Я сделал простой калькулятор тарифов, который конвертирует тарифы на почасовой, еженедельной, ежемесячной и годовой основе. Когда я изменю соответствующий тариф, другие тарифы будут обновляться соответственно.
Код приложения выглядит следующим образом:
import React, { useState } from 'react';
import {
CssBaseline,
Container,
Typography,
TextField
} from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles(theme => ({
paper: {
marginTop: theme.spacing(8), // = 4 * 2
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}
}));
function App() {
const classes = useStyles();
const [hourlyRate, setHourlyRate] = useState(10);
const [workHour, setWorkHour] = useState(40);
const [weeklyRate, setWeeklyRate] = useState(400);
const [monthlyRate, setMonthlyRate] = useState(1600);
const [yearlyRate, setYearlyRate] = useState(19200);
const tryConvert = ({ name, value }) => {
if (name === 'work-hours') {
setWorkHour(value);
setWeeklyRate(value * hourlyRate);
setMonthlyRate(value * hourlyRate * 4);
setYearlyRate(value * hourlyRate * 4 * 12);
} else if (name === 'hourly-rate') {
setHourlyRate(value);
setWeeklyRate(value * workHour);
setMonthlyRate(value * workHour * 4);
setYearlyRate(value * workHour * 4 * 12);
} else if (name === 'weekly-rate') {
setWeeklyRate(value);
setHourlyRate(value / workHour);
setMonthlyRate(value * 4);
setYearlyRate(value * 4 * 12);
} else if (name === 'monthly-rate') {
setMonthlyRate(value);
setWeeklyRate(value / 4);
setHourlyRate(value / workHour / 4);
setYearlyRate(value * 12);
} else if (name === 'yearly-rate') {
setYearlyRate(value);
setMonthlyRate(value / 12);
setWeeklyRate(value / 12 / 4);
setHourlyRate(value / 12 / 4 / workHour);
}
};
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Typography component="h1" variant="h5">
Rate Kalkulator
</Typography>
<TextField
variant="outlined"
margin="normal"
id="hourly-rate"
label="Hourly Rate"
name="hourly-rate"
autoFocus
inputProps={{ 'data-testid': 'hourly-rate' }}
value={hourlyRate ? hourlyRate : 0}
onChange={event => tryConvert(event.target)}
/>
<TextField
variant="outlined"
margin="normal"
id="work-hours"
label="Work Hours"
name="work-hours"
inputProps={{ 'data-testid': 'work-hours' }}
value={workHour}
onChange={event => tryConvert(event.target)}
/>
<TextField
variant="outlined"
margin="normal"
id="weekly-rate"
label="Weekly Rate"
name="weekly-rate"
inputProps={{ 'data-testid': 'weekly-rate' }}
value={weeklyRate ? weeklyRate : 0}
onChange={event => tryConvert(event.target)}
/>
<TextField
variant="outlined"
margin="normal"
id="monthly-rate"
label="Monthly Rate"
name="monthly-rate"
inputProps={{ 'data-testid': 'monthly-rate' }}
value={monthlyRate ? monthlyRate : 0}
onChange={event => tryConvert(event.target)}
/>
<TextField
variant="outlined"
margin="normal"
id="yearly-rate"
label="Yearly Rate"
name="yearly-rate"
inputProps={{ 'data-testid': 'yearly-rate' }}
value={yearlyRate ? yearlyRate : 0}
onChange={event => tryConvert(event.target)}
/>
</div>
</Container>
);
}
export default App;
Ссылка Codesandbox - tryConvert
Оценить Kalkulator - tryConvert
Приложение работало, как и ожидалось, насколько я тестировал, еще не работало на крайних случаях.
Упрощение конвертации курсов
Я пытаюсь упростить конвертацию tryConvert
с другими React Hooks, но не удалось. Это код для преобразования из приведенных выше кодов:
const tryConvert = ({ name, value }) => {
if (name === 'work-hours') {
setWorkHour(value);
setWeeklyRate(value * hourlyRate);
setMonthlyRate(value * hourlyRate * 4);
setYearlyRate(value * hourlyRate * 4 * 12);
} else if (name === 'hourly-rate') {
setHourlyRate(value);
setWeeklyRate(value * workHour);
setMonthlyRate(value * workHour * 4);
setYearlyRate(value * workHour * 4 * 12);
} else if (name === 'weekly-rate') {
setWeeklyRate(value);
setHourlyRate(value / workHour);
setMonthlyRate(value * 4);
setYearlyRate(value * 4 * 12);
} else if (name === 'monthly-rate') {
setMonthlyRate(value);
setWeeklyRate(value / 4);
setHourlyRate(value / workHour / 4);
setYearlyRate(value * 12);
} else if (name === 'yearly-rate') {
setYearlyRate(value);
setMonthlyRate(value / 12);
setWeeklyRate(value / 12 / 4);
setHourlyRate(value / 12 / 4 / workHour);
}
};
Моя попытка использования useEffect
Я пытался использовать useEffect для добавления обратных вызовов при изменении состояний. Коды ниже иллюстрируют то, что я пробовал:
import React, { useState, useEffect } from 'react';
const [hourlyRate, setHourlyRate] = useState(10);
const [workHour, setWorkHour] = useState(40);
const [weeklyRate, setWeeklyRate] = useState(400);
const [monthlyRate, setMonthlyRate] = useState(1600);
const [yearlyRate, setYearlyRate] = useState(19200);
useEffect(() => {
setWeeklyRate(hourlyRate * workHour);
setMonthlyRate(hourlyRate * workHour * 4);
setYearlyRate(hourlyRate * workHour * 4 * 12);
}, [hourlyRate, workHour]);
useEffect(() => {
setHourlyRate(weeklyRate / workHour);
setMonthlyRate(weeklyRate * 4);
setYearlyRate(weeklyRate * 4 * 12);
}, [weeklyRate, workHour]);
useEffect(() => {
setHourlyRate(monthlyRate / 4 / workHour);
setWeeklyRate(monthlyRate / 4);
setYearlyRate(monthlyRate * 12);
}, [monthlyRate, workHour]);
useEffect(() => {
setHourlyRate(yearlyRate / 12 / 4 / workHour);
setWeeklyRate(yearlyRate / 12 / 4);
setMonthlyRate(yearlyRate / 12);
}, [yearlyRate, workHour]);
Если я использую этот подход, при изменении workHour
преобразование не будет работать должным образом. Я думаю, это потому, что workHour
стал зависимым от 4 различных useEffect
. Я до сих пор не уверен в этом.
Ссылка Codesandbox - useEffect
Rate Kalkulator - useEffect
если вы измените рабочий час, преобразование не будет работать
В настоящее время я пробую другие подходы, использующие useReduce, но я все еще не уверен, будет ли это лучшим способом конвертировать ставки.
Как лучше всего упростить мой tryConvert?
Буду признателен за любую помощь в этом.