代码之家  ›  专栏  ›  技术社区  ›  Salvo

函数无法读取useState参数

  •  0
  • Salvo  · 技术社区  · 2 年前

    当我启动该功能时,我正在用React Native和Firebase实时数据库构建一个应用程序 addItem 我从数据库获取的对象中唯一的参数是 id ,其他参数返回为 '' ,我试过使用 console.log() 文本输入也很好,我已经多次使用这种配置,这是第一次。

    export default function NewItem() {
    
        const [name, setName] = useState('');
        const [price, setPrice] = useState('');
        const [description, setDescription] = useState('');
    
        useEffect(() => {
            navigation.setOptions({
                headerRight: () => (
                    <TouchableOpacity onPress={addItem}>
                        <Text style={{fontWeight:'bold'}}>ADD ITEM</Text>
                    </TouchableOpacity>
                )
            })
        }, [])
    
        const addItem = () => {
    
            const changes = ref(db, 'path')
            get(changes).then( async (snapshot) => {
                if (snapshot.val().data !== undefined) {
    
                    let array = []
    
                    let object = {
                        "id": `${id}`,
                        "name": name,
                        "price": price,
                        "description": description,
                    }
    
                    array.push(object)
                    
                    update(changes, {
                        data: array
                    })
    
                }
            })
        }
    
      return (
        <TouchableWithoutFeedback>
                <TextInput
                    onChangeText={(e) => setName(e)}
                />
                <TextInput
                    onChangeText={(e) => setShippingPrice(e)}
                        />
                <TextInput
                    onChangeText={(e) => setPrice(e)}
                />
                <TextInput
                    onChangeText={(e) => setDescription(e)}
                />
        </TouchableWithoutFeedback>
      )
    }
    
    1 回复  |  直到 2 年前
        1
  •  1
  •   Drew Reese    2 年前

    addItem 是自 useEffect 钩子只运行一次,并在初始状态下关闭。您可能可以通过添加 增加列表项 函数调用依赖项数组。

    useEffect(() => {
      navigation.setOptions({
        headerRight: () => (
          <TouchableOpacity onPress={addItem}>
            <Text style={{fontWeight:'bold'}}>ADD ITEM</Text>
          </TouchableOpacity>
        )
      })
    }, [addItem]);
    

    你应该记住 增加列表项 回调处理程序,以进一步减少 使用效果 上面的钩子重新封装了回调/状态。

    const addItem = React.useCallback(() => {
      const changes = ref(db, 'path');
      get(changes)
        .then(async (snapshot) => {
          if (snapshot.val().data !== undefined) {
            const data = [{
              "id": `${id}`,
              name,
              price,
              description,
            }];
                    
            update(changes, { data });
          }
        })
    }, [name, price, description]);
    

    或者,您可以在React ref中缓存所有状态值,并通过回调中的ref访问它们。

    例子:

    export default function NewItem() {
      const [name, setName] = useState('');
      const [price, setPrice] = useState('');
      const [description, setDescription] = useState('');
    
      const stateRef = React.useRef({
        name,
        price,
        description,
      });
    
      useEffect(() => {
        stateRef.current = { name, price, description };
      }, [name, price, description]);
    
      useEffect(() => {
        navigation.setOptions({
          headerRight: () => (
            <TouchableOpacity onPress={addItem}>
              <Text style={{fontWeight:'bold'}}>ADD ITEM</Text>
            </TouchableOpacity>
          )
        })
      }, []);
    
      const addItem = () => {
        const changes = ref(db, 'path');
        get(changes)
          .then(async (snapshot) => {
            if (snapshot.val().data !== undefined) {
              const { name, price, description } = stateRef.current;
              const data = [{
                "id": `${id}`,
                name,
                price,
                description,
              }];
                    
              update(changes, { data });
            }
          })
      }
    
      return (...);
    }
    
        2
  •  1
  •   Cesare Polonara    2 年前

    正如Drew Reese指出的,这是典型的 陈旧状态 使用JavaScript闭包时,React中的问题。 使用效果 将一个函数作为参数,在该函数中使用另一个函数 增加列表项 这是在 反应组分 和使用 反应状态 .这种情况下发生的是 增加列表项 在以下情况下被记忆 使用效果 执行时,它就像一张静态的图片。不幸地 增加列表项 不是一个纯粹的函数,它依赖于React状态,所以它在React生命周期中会发生变化 使用效果 它的回调版本将保持静态。这是因为你初始化了 使用效果 将空数组用作第二个参数[]的钩子。

    这就是为什么我们要引入 依赖项数组 ,数组中的值决定何时必须重新计算钩子中的回调。有一个非常重要的问题 掉毛 强制您将回调的所有依赖项放入deps数组中的规则: @反应钩/详尽的DEP 避免许多细微的错误和不当行为。

    这应该是在您的案例中使用React钩子的正确方法,以提高性能,避免错误和对Reender进行不必要的计算:

    export default function NewItem() {
    
        const [name, setName] = useState('');
        const [price, setPrice] = useState('');
        const [description, setDescription] = useState('');
    
        useEffect(() => {
            navigation.setOptions({
                headerRight: () => (
                    <TouchableOpacity onPress={addItem}>
                        <Text style={{fontWeight:'bold'}}>ADD ITEM</Text>
                    </TouchableOpacity>
                )
            })
        }, [addItem])
    
        const addItem = useCallback(() => {
    
            const changes = ref(db, 'path')
            get(changes).then( async (snapshot) => {
                if (snapshot.val().data !== undefined) {
    
                    const array = []
    
                    const object = {
                        "id": `${id}`,
                        "name": name,
                        "price": price,
                        "description": description,
                    }
    
                    array.push(object)
                    
                    update(changes, {
                        data: array
                    })
    
                }
            })
        },[name, price, description ])
    
      return (
        <TouchableWithoutFeedback>
                <TextInput
                    onChangeText={(e) => setName(e)}
                />
                <TextInput
                    onChangeText={(e) => setShippingPrice(e)}
                        />
                <TextInput
                    onChangeText={(e) => setPrice(e)}
                />
                <TextInput
                    onChangeText={(e) => setDescription(e)}
                />
        </TouchableWithoutFeedback>
      )
    }