【问题标题】:useCallback Hooks getting old state values and not updatinguseCallback Hooks 获取旧状态值而不更新
【发布时间】:2020-08-25 19:17:52
【问题描述】:

我的回调在一次又一次调用后返回相同的状态

我是反应类中的反应钩子的新手,我本可以使用 shouldcomponentupdate 并且可以解决这个问题

但是 usecallback 钩子中没有参数

import React, {
  useLayoutEffect,
  useState,
  useCallback,
  useEffect,
} from "react";
import { StyleSheet, Text, View, Platform, YellowBox } from "react-native";
import { HeaderButtons, Item } from "react-navigation-header-buttons";
import HeaderButton from "../components/HeaderButton";
import { Switch } from "react-native-paper";
import Colors from "../constants/Colors";
//check use callback value first

YellowBox.ignoreWarnings([
  "Non-serializable values were found in the navigation state",
]);

const FilterSwitch = ({ label, state, onChange }) => (
  <View style={styles.filterContainer}>
    <Text>{label}</Text>
    <Switch
      value={state}
      trackColor={{ true: Colors.primaryColor }}
      thumbColor={Platform.OS === "android" ? Colors.primaryColor : ""}
      onValueChange={onChange}
    />
  </View>
);

const FiltersScreen = ({ navigation }) => {
  const [isGlutenFree, setIsGlutenFree] = useState(false);
  const [isLactoseFree, setIsLactoseFree] = useState(false);
  const [isVegan, setIsVegan] = useState(false);
  const [isVegetarian, setIsVegetarian] = useState(false);

  const saveFilters = useCallback(() => {
    console.log(isGlutenFree);
    const appliedFilters = {
      glutenFree: isGlutenFree,
      lactoseFree: isLactoseFree,
      vegan: isVegan,
      isVegetarian: isVegetarian,
    };

    console.log(appliedFilters);
  }, [isGlutenFree, isLactoseFree, isVegan, isVegetarian]);


  useLayoutEffect(() => {
    navigation.setOptions({
      headerTitle: "Filter Meals",
      headerLeft: () => (
        <HeaderButtons HeaderButtonComponent={HeaderButton}>
          <Item
            title="Menu"
            iconName="ios-menu"
            onPress={() => {
              navigation.toggleDrawer();
            }}
          />
        </HeaderButtons>
      ),
      headerRight: () => (
        <HeaderButtons HeaderButtonComponent={HeaderButton}>
          <Item
            title="Save"
            iconName="ios-save"
            onPress={() => saveFilters()}
          />
        </HeaderButtons>
      ),
    });
  }, [navigation]);
  return (
    <View style={styles.screen}>
      <Text style={styles.title}>Available Filters / Restrictions</Text>
      <FilterSwitch
        label="Gluten Free"
        state={isGlutenFree}
        onChange={(newValue) => {
          setIsGlutenFree(newValue);
        }}
      />
      <FilterSwitch
        label="Lactos Free"
        state={isLactoseFree}
        onChange={(newValue) => setIsLactoseFree(newValue)}
      />
      <FilterSwitch
        label="Vegan Free"
        state={isVegan}
        onChange={(newValue) => setIsVegan(newValue)}
      />
      <FilterSwitch
        label="Vegetarian Free"
        state={isVegetarian}
        onChange={(newValue) => setIsVegetarian(newValue)}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  screen: {
    flex: 1,
    alignItems: "center",
  },
  filterContainer: {
    flexDirection: "row",
    justifyContent: "space-between",
    alignItems: "center",
    width: "80%",
    marginVertical: 15,
  },
  title: {
    fontFamily: "open-sans-bold",
    fontSize: 22,
    margin: 20,
    textAlign: "center",
  },
});
export default FiltersScreen;

我该如何解决这个问题? 我已阅读官方文档,但我找不到任何相关问题

【问题讨论】:

  • useCallback 只是记住一个回调(确保它的引用保持不变,除非它的依赖项之一发生了变化。看起来你写的那个没有做任何事情(只是创建一个对象并记录它) ). 例如,如果你打电话给setIsVegetarian,它会改变
  • 我正在调用 FilterSwitch 自定义组件上的每个 setState 调用,并且我提供了每个值,即使我的状态在每次渲染时都会发生变化
  • 您的 useNavigationEffect 挂钩没有您的 saveFilters 回调作为依赖项,因此它永远不会调用“新”回调(状态已更改)。将其添加到您的依赖项列表中

标签: javascript reactjs react-native react-hooks usecallback


【解决方案1】:

您的代码的问题是,即使您已经为 useCallback 提供了所有依赖数组,您也只使用了 onPress={() =&gt; saveFilters()} 内函数的 first closure value,因为此代码在 useLayoutEffect 内执行,并且仅在 navigation 更改时运行

这里的解决方案是在navigationsaveFilters 上都更改update navigation options

useLayoutEffect(() => {
    navigation.setOptions({
      headerTitle: "Filter Meals",
      headerLeft: () => (
        <HeaderButtons HeaderButtonComponent={HeaderButton}>
          <Item
            title="Menu"
            iconName="ios-menu"
            onPress={() => {
              navigation.toggleDrawer();
            }}
          />
        </HeaderButtons>
      ),
      headerRight: () => (
        <HeaderButtons HeaderButtonComponent={HeaderButton}>
          <Item
            title="Save"
            iconName="ios-save"
            onPress={() => saveFilters()}
          />
        </HeaderButtons>
      ),
    });
  }, [navigation, saveFilters]);

P.S. 在这种情况下,我觉得 hooks 的实现有时会变得笨拙或效率低下。也调试 closures 比调试 context(这个在 类组件)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2021-07-27
    • 1970-01-01
    • 1970-01-01
    • 2020-11-05
    • 1970-01-01
    相关资源
    最近更新 更多