Я добавил TextField из библиотеки MUI и использовал ловушку useRef для захвата значения "в реальном времени", когда пользователь что-то вводит. Намерение состоит в том, чтобы отфильтровать только те ставки, которые включают символы, которые он вводит. На данный момент:

Object.keys(rates["rates"]) // ["EUR", "RON", "CZK", ...]

Я добавил форму и хочу, чтобы она оставалась постоянной, но кнопки должны меняться динамически. Если пользователь ничего не набрал, я хочу вернуть все (как будто ничего не фильтруется)

Моя попытка:

import React, {useEffect, useRef, useState} from 'react'
import Button from '@mui/material/Button';
import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';
import TextField from '@mui/material/TextField';

const RatesButton = () => {
    const rateRef = useRef('')
    const [rates, setRates] = useState([]);
    useEffect(
        () => {
            fetch("https://api.vatcomply.com/rates")
                .then(ratesResponse => ratesResponse.json())
                .then(rates => setRates(rates));
        }
        , [])


    if (rates.length === 0) {
        return (
            <Box sx={{display: 'flex', justifyContent: 'center'}}>
                <CircularProgress/>
            </Box>
        )
    }

    const rateSearch = () => {
        Object.keys(rates["rates"]).filter(
            rate => rate.includes(rateRef.current.value)
        ).map(rate => {

                return (
                    <Button>
                        {rate}
                    </Button>
                )
            }
        )

    }

    return (
        <>
            <br/>
            <TextField id="rate-search" onChange={rateSearch} inputRef={rateRef} label="Rate" variant="outlined"/>
        </>
    )
}


export default RatesButton

Я думаю, это работает хорошо, я могу получить доступ к ссылке на ввод пользователя, отфильтровать все ставки, содержащие буквы, и сопоставить каждую с MUI Button. Проблема в том, что они как-то не отображаются, и я довольно растерялся, довольно сбивает с толку, как я могу возвращаться из двух разных функций одновременно, сохраняя при этом одну постоянную (поле ввода)

Picture of the input

Кнопки, к сожалению, не отображаются ...

2
user1530682 15 Окт 2021 в 19:57

2 ответа

Лучший ответ

Вам следует использовать контролируемый режим и сохранить свой TextField значение в состоянии, использующем useState вместо useRef, потому что изменение значения ref не запускает повторную визуализацию, поэтому пользовательский интерфейс не обновляется. В вашем коде много других неправильных вещей, я все исправил, не стесняйтесь спрашивать меня, если вы ничего не понимаете:

const RatesButton = () => {
  const [value, setValue] = useState("");
  const [rates, setRates] = useState({});

  useEffect(() => {
    fetch("https://api.vatcomply.com/rates")
      .then((ratesResponse) => ratesResponse.json())
      .then((rates) => setRates(rates.rates ?? {}));
  }, []);

  return (
    <>
      {Object.keys(rates).length === 0 && (
        <Box sx={{ display: "flex", justifyContent: "center" }}>
          <CircularProgress />
        </Box>
      )}
      {Object.keys(rates)
        .filter((rate) => rate.toLowerCase().includes(value.toLowerCase()))
        .map((rate) => {
          return <Button>{rate}</Button>;
        })}
      <br />
      <TextField
        id="rate-search"
        onChange={(e) => setValue(e.target.value)}
        // inputRef={value}
        label="Rate"
        variant="outlined"
      />
    </>
  );
};

Живая демонстрация

Codesandbox Demo

1
NearHuscarl 15 Окт 2021 в 17:20
    import React, {useState} from 'react';
    import { throttle } from 'lodash';

    const RatesButton = () => {
      const [value, setValue] = useState("");
      const [rates, setRates] = useState({});

      useEffect(() => {
        fetch("https://api.vatcomply.com/rates")
          .then((ratesResponse) => ratesResponse.json())
          .then((rates) => setRates(rates.rates ?? {}));
      }, []);
      
      const handleChange = (e) => setValue(e.target.value);
      
      // it will prevent multiple render during fast typing
      const throttledChange = throttle(handleChange, 400);

      return (
        <>
          {Object.keys(rates).length === 0 && (
            <Box sx={{ display: "flex", justifyContent: "center" }}>
              <CircularProgress />
            </Box>
          )}
          {Object.keys(rates)
            .filter((rate) => rate.toLowerCase().includes(value.toLowerCase()))
            .map((rate) => {
              return <Button>{rate}</Button>;
            })}
          <br />
          <TextField
            id="rate-search"
            onChange={throttledChange} // don't use arrow function
            label="Rate"
            variant="outlined"
          />
        </>
      );
    };
0
DilipCoder 15 Окт 2021 в 18:01