React hooks setstate change отражает только первое изменение - PullRequest
0 голосов
/ 18 июня 2020

Я пытаюсь создать страницу пищевого фильтра, на которой пользователь нажимает кнопки, чтобы указать свои предпочтения, чтобы при подтверждении я мог сохранить предпочтения пользователя как на объекте с ключами "area", "cuisine" and "price". После попытки различных комбинаций зарегистрированный объект, который я получаю, продолжает отражать только изменение в первом обновлении, которое является областью. {"area": "South", "cuisine": Array [], "price": -Infinity } вместо {"area":"South", "cuisine": "Japanese Cuisine", "price": 3}. Как мне справиться с этой асинхронной c природой setstate, чтобы все обновления были правильными? (функции нажатия ручки передаются детскому компоненту для кухни и цены)

enter image description here

Фильтр. js

const [filters, setFilters] = React.useState({});

    React.useEffect(() => {
        setFilters({ area: "", cuisine: "", price: 0 });
    }, []);

    const handleAreaPress = (area) => {
        setFilters((prevState) => ({ ...prevState, area: area }));
    };

    const handleCuisinePress = (cuisine) => {
        setFilters((prevState) => ({ ...prevState, cuisine: cuisine }));
    };

    const handlePricePress = (price) => {
        let max = Math.max(...price);
        setFilters((prevState) => ({ ...prevState, price: max }));
    };

    const handleConfirmPress = () => {
        console.log(filters);  // expected log to be {"area":"South", "cuisine": "Japanese Cuisine", "price": 3}
    };

Площадь. js

const AreaSelection = ({ handleAreaPress }) => {
    const [selected, setSelected] = React.useState([]);
    const areas = ["North", "South", "East", "West", "Central"];

    const handlePress = (area) => {
        setSelected(area);
    };

    const buttons = () =>
        areas.map((items) => (
            <TouchableOpacity
                key={items}
                onPress={() => {
                    handlePress(items);
                    handleAreaPress(items);
                }}
                style={[
                    styles.button,
                    {
                        backgroundColor: selected.includes(items)
                            ? "silver"
                            : "white",
                    },
                ]}
            >

Кухня. js

const CuisineSelection = ({ handleCuisinePress }) => {
    const [selected, setSelected] = React.useState([]);
    const cuisine = [
        "Asian",
        "Western",
        "Chinese",
        "Korean",
        "Indian",
        "Japanese",
        "Cafe",
        "Local",
    ];

    const handlePress = (cuisine) => {
        selected.includes(cuisine)
            ? setSelected(selected.filter((s) => s !== cuisine))
            : setSelected([...selected, cuisine]);
    };

    const buttons = () =>
        cuisine.map((items) => (
            <TouchableOpacity
                key={items}
                onPress={() => {
                    handlePress(items);
                    handleCuisinePress(selected);
                }}
                style={[
                    styles.button,
                    {
                        backgroundColor: selected.includes(items)
                            ? "silver"
                            : "white",
                    },
                ]}
            >

Ответы [ 3 ]

1 голос
/ 18 июня 2020

Код города действительно работает правильно. Проблема в этом коде, где вы вызываете две функции, устанавливающие состояние:

    handlePress(items);
    handleCuisinePress(selected);

handlePress устанавливает состояние внутреннего компонента, а затем handleCuisinePress считывает это состояние и устанавливает его в фильтрах. Однако, поскольку состояние настройки - asyn c при вызове handleCuisinePress, оно использует старые значения состояния, поскольку результаты handlePress еще не применяются.

Лучший способ справиться с этим - избавиться от внутреннего состояния компонента и прочитать его прямо из фильтров:

// Declare array outside of component to not create it on every render
const cuisine = [
        "Asian",
        "Western",
        "Chinese",
        "Korean",
        "Indian",
        "Japanese",
        "Cafe",
        "Local",
    ];

const CuisineSelection = ({ handleCuisinePress, cuisine }) => {
    const buttons = () =>
        cuisine.map((items) => (
            <TouchableOpacity
                key={items}
                onPress={() => {
                    handleCuisinePress(items);
                }}

            >
1 голос
/ 18 июня 2020
 const handlePress = (cuisine) => {
    let newSelected = [];

    if (selected.includes(cuisine)) {
      newSelected = selected.filter((s) => s !== cuisine);
    } else {
      newSelected = selected.concat(cuisine);
    }

    setSelected(cuisine);
    handleCuisinePress(newSelected);
};

Состояние selected, которое вы передаете в handleCuisinePress, устарело, вы не должны на него полагаться, просто передайте новое состояние, которое вы рассчитали в handlePress, на handleCuisinePress

0 голосов
/ 18 июня 2020

Вы можете определить диапазон ожидаемых значений и условно вернуться к значению по умолчанию.

    const handlePricePress = (price) => {
        const max = price >= 0 ? Math.max(...price) : 0;
        setFilters((prevState) => ({ ...prevState, price: max }));
    };
...