簡體   English   中英

無法從 React Native 中的父組件更新子組件的屬性

[英]Can’t update the property of a child component from a parent component in React Native

我是 React Native 移動開發的新手。 我正在使用世博會。 我無法管理一個州。

我有一個SearchTextBox組件,我想從父組件設置text屬性,但是我無法使用useState管理它。

import React, { useState, useEffect } from "react";
import { TouchableOpacity } from "react-native-gesture-handler";
import { Ionicons } from "@expo/vector-icons";
import { StyleSheet, TextInput, View } from "react-native";

import defaultStyles from "../config/styles";

function SearchTextBox({
  searchQuery,
  width = "100%",
  onSearch,
  ...otherProps
}) {
  const [query, setQuery] = useState(searchQuery);
  const [isClearable, setIsClearable] = useState(
    query != null && query.length > 0
  );

  const onChange = (e) => {
    const { text } = e.nativeEvent;
    setQuery(text);
    const length = text.length;
    setIsClearable(length > 0);
    if (length >= 2 && onSearch) onSearch(text);
  };

  const onClear = () => {
    setQuery("");
    setIsClearable(false);
  };

  return (
    <View style={styles.container}>
      <View
        style={{
          width: 72,
        }}
      >
        <Ionicons
          name="md-search"
          size={32}
          color={defaultStyles.colors.medium}
          style={styles.icon}
        />
      </View>

      <View
        style={{
          flex: 2,
        }}
      >
        <TextInput
          autoCorrect={false}
          autoFocus={false}
          autoCapitalize="none"
          placeholder="Search"
          placeholderTextColor={defaultStyles.colors.medium}
          style={[defaultStyles.text, styles.text]}
          onChange={onChange}
          value={query}
          {...otherProps}
        />
      </View>
      {isClearable && (
        <View>
          <TouchableOpacity onPress={onClear}>
            <Ionicons
              name="md-close"
              size={32}
              color={defaultStyles.colors.medium}
              style={styles.icon}
            />
          </TouchableOpacity>
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    backgroundColor: defaultStyles.colors.light,
    borderRadius: 24,
    flexDirection: "row",
    flex: 1,
    marginVertical: 10,
  },
  icon: {
    margin: 15,
    paddingRight: 15,
  },
  text: {
    flexGrow: 1,
    fontSize: 18,
  },
});

export default SearchTextBox;

我是這樣使用的:


import React, { useState, useEffect, useRef } from "react";
import { View, StyleSheet, FlatList, AsyncStorage } from "react-native";
import { AdMobBanner } from "expo-ads-admob";
import * as Device from "expo-device";

import { ListItem, ListItemSeparator } from "../components/lists/";
import Screen from "../components/Screen";
import SearchTextBox from "../components/SearchTextBox";
import AnimatedTextList from "../components/AnimatedTextList";

import colors from "../config/colors";

import searchApi from "../api/search";
import useApi from "../hooks/useApi";
import ads from "../config/ads";

function HomeScreen() {
  const search = useApi(searchApi.search);
  const [data, setData] = useState([]);
  const [showRandomWords, setShowRandomWords] = useState(true);
  const [randomWords, setRandomWords] = useState([]);
  const [bannerType, setBannerType] = useState("banner");
  const [initialQuery, setInitialQuery] = useState();

  const getDeviceTypeAsync = async () => {
    const deviceType = await Device.getDeviceTypeAsync();
    setBannerType(
      deviceType === Device.DeviceType.TABLET ? "fullBanner" : "banner"
    );
  };

  useEffect(() => {
    getDeviceTypeAsync;
  }, []);

  const onSearch = async (value) => {
    setShowRandomWords(value == null || value == undefined || value === "");
    const result = await search.request(value);
    if (!result.ok) return;
    setData(result.data.data);
  };

  useEffect(() => {
    const getRandomWords = async () => {
      try {
        const result = await AsyncStorage.getItem("random_words");
        if (!result) return;
        setRandomWords(JSON.parse(result));
        setShowRandomWords(true);
      } catch (error) {
        console.log(error);
      }
    };
    getRandomWords();
  }, []);

  const bannerError = (error) => {
    console.log("An error occured while trying to show AdMob", error);
  };

  const onRandomWordPress = (item) => {
    setInitialQuery(item.title);
    onSearch(initialQuery);
  };

  return (
    <Screen>
      <View style={styles.searchBox}>
        <SearchTextBox
          searchQuery={initialQuery}
          width="90%"
          onSearch={onSearch}
        />
      </View>

      {showRandomWords && (
        <View>
          <AnimatedTextList items={randomWords} onPress={onRandomWordPress} />
        </View>
      )}

      <View style={styles.result}>
        <FlatList
          data={data}
          keyExtractor={(word) => word.id.toString()}
          renderItem={({ item }) => (
            <ListItem title={item.word} subTitle={item.descp} />
          )}
          ItemSeparatorComponent={ListItemSeparator}
        />
      </View>
      <View style={styles.bottomBanner}>
        <AdMobBanner
          style={styles.bottomBanner}
          bannerSize={bannerType}
          adUnitID={ads.unitID}
          servePersonalizedAds
          didFailToReceiveAdWithError={bannerError}
        />
      </View>
    </Screen>
  );
}

const styles = StyleSheet.create({
  bottomBanner: {
    alignContent: "center",
    alignItems: "center",
    alignSelf: "center",
    bottom: 0,
    position: "absolute",
    width: "100%",
  },
  container: {
    flex: 1,
    alignItems: "center",
    width: "100%",
    flexDirection: "column",
  },
  searchBox: {
    backgroundColor: colors.white,
    height: 100,
    width: "100%",
    padding: 10,
  },
  result: {
    width: "100%",
    flex: 1,
  },
});

export default HomeScreen;

這是我綁定的屬性

<SearchTextBox
          searchQuery={initialQuery}
          width="90%"
          onSearch={onSearch}
        />

onRandomWordPress我設置了變量,但它不會更新輸入的文本。

const onRandomWordPress = (item) => {
    setInitialQuery(item.title);
    onSearch(initialQuery);
  };

這樣做的正確方法是什么,或者我的實現有什么問題?

謝謝!

您不應該將此處的random word傳遞給您的onSearch函數。

const onRandomWordPress = (item) => {
    setInitialQuery(item.title);
    onSearch(item.title);
};

這是我如何實現的。 我將查詢綁定到父組件(總是),從父組件管理幾乎所有內容。

現在,我有一個更干凈的SearchTextBox組件。

function SearchTextBox({
  searchQuery,
  onTextChange,
  onQueryClear,
  width = "100%",
  ...otherProps
}) {
  const hasSearchQuery = () => {
    return searchQuery != null && searchQuery.length > 0;
  };

  const onChange = (e) => {
    const { text } = e.nativeEvent;
    onTextChange(text);
  };

  return (
    <View style={styles.container}>
      <View
        style={{
          width: 72,
        }}
      >
        <Ionicons
          name="md-search"
          size={32}
          color={defaultStyles.colors.medium}
          style={styles.icon}
        />
      </View>

      <View
        style={{
          flex: 2,
        }}
      >
        <TextInput
          autoCorrect={false}
          autoFocus={false}
          autoCapitalize="none"
          placeholderTextColor={defaultStyles.colors.medium}
          style={[defaultStyles.text, styles.text]}
          onChange={onChange}
          value={searchQuery}
          {...otherProps}
        />
      </View>
      {hasSearchQuery() && (
        <View>
          <TouchableOpacity onPress={onQueryClear}>
            <Ionicons
              name="md-close"
              size={32}
              color={defaultStyles.colors.medium}
              style={styles.icon}
            />
          </TouchableOpacity>
        </View>
      )}
    </View>
  );
}

並從父管理部分:

function HomeScreen() {
  const search = useApi(searchApi.search);
  const [data, setData] = useState([]);
  const [showRandomWords, setShowRandomWords] = useState(true);
  const [randomWords, setRandomWords] = useState([]);
  const [initialQuery, setInitialQuery] = useState();

  const onSearch = async (value) => {
    const isEmptyQuery = value == null || value == undefined || value === "";
    setShowRandomWords(isEmptyQuery);
    const result = await search.request(value);
    if (!result.ok) return;
    setData(result.data.data);
  };

  const onQueryClear = () => {
    setInitialQuery("");
    setData([]);
    setShowRandomWords(true);
  };
  
  const onTextChange = (text) => {
    setInitialQuery(text);
    if (text.length > 2) onSearch(text);
  };

  const onRandomWordPress = (item) => {
    setInitialQuery(item.title);
    onSearch(item.title);
  };

  useEffect(() => {
    getRandomWords();
  }, []);

  return (
    <Screen>
      <View style={styles.searchBox}>
        <SearchTextBox
          searchQuery={initialQuery}
          onTextChange={onTextChange}
          onQueryClear={onQueryClear}
          width="90%"
        />
      </View>

      {showRandomWords && (
        <View>
          <AnimatedTextList items={randomWords} onPress={onRandomWordPress} />
        </View>
      )}

      <View style={styles.result}>
        <FlatList
          data={data}
          keyExtractor={(word) => word.id.toString()}
          renderItem={({ item }) => (
            <ListItem title={item.word} subTitle={item.descp} />
          )}
          ItemSeparatorComponent={ListItemSeparator}
        />
      </View>
    </Screen>
  );
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM