undefined 不是对象,加载后如何访问钩子刷新的对象

Undefined is not an object, how do I access object refreshed by hooks after it is loaded

在我的应用程序中,我输入了一个字符串,然后在 rest api 调用中立即调用该字符串,并根据输入的名称返回包含所有饮料的 json 对象。然后我想显示该对象的特定部分,例如名称,但在访问该对象的该部分时出现未定义错误,稍后我将详细说明。 我正在实现 react-navigation 和 react-elements,变量由 hooks 刷新。

export default class App extends Component {
    render() {    
        console.log('change')
        return (
            <NavigationContainer>
                <Drawer.Navigator initialRouteName="Home">
                    <Drawer.Screen name="Home" component={HomeScreen} />
                    <Drawer.Screen name="Notifications" component={NotificationsScreen} />
                </Drawer.Navigator>
            </NavigationContainer>   
        );
    }
}

问题出在首页,我的代码可以在每个键入的字符后显示完整的对象:我可以显示包含我输入的查询名称的所有饮料的对象。但是,我想显示一个特定的对象中的元素,例如第一个 id (object.drinks[0].idDrink),我假设它还没有加载,并且出现了未定义的错误。我之前在没有钩子的情况下可以访问 id,那部分没有错。我假设我破坏了实现许多刷新我的应用程序的钩子的东西。

function HomeScreen() {
  
    const [query, setQuery] = useState('');
    const [jsonData, setJsonData] = useState([]);
    const [loading, setLoading] = useState(true);
    console.log(loading, '1') 
    useEffect(() => {
        setLoading(true);
        console.log(loading, '2') 

        fetch('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=' + query, {
            method: 'GET',
        })
            .then(response => response.json())
            .then(jsonD => setJsonData(jsonD), 
                setLoading(false),
                console.log(loading, '3'))
            .catch(error => {
                console.error(error);
            });
    }, [query])  

    return (
        <ScrollView >
            <Text>Bartender</Text>
            <SearchBar
                placeholder="Type Here..."
                onChangeText={setQuery}
                value={query}
            />
           <>
                { 
                    loading ? console.log('waiting for loading') : console.log(jsonData.drinks[0].idDrink)
                }
           </>    
        </ScrollView >
    );
}

我试图通过设置加载变量来解决这个问题,它会在对象完全加载后渲染它,但它并没有解决它。

如果我 运行 应用程序显示控制台日志而不是特定元素:

加载中? console.log('waiting for loading') : console.log('the data should be loaded'),

这是输出:

[Thu Dec 17 2020 20:20:07.902]  LOG      change
[Thu Dec 17 2020 20:20:08.159]  LOG      true 1
[Thu Dec 17 2020 20:20:08.175]  LOG      waiting for loading
[Thu Dec 17 2020 20:20:13.218]  LOG      true 2
[Thu Dec 17 2020 20:20:13.284]  LOG      true 3
[Thu Dec 17 2020 20:20:13.451]  LOG      false 1
[Thu Dec 17 2020 20:20:13.486]  LOG      the data should be loaded
[Thu Dec 17 2020 20:20:14.761]  LOG      false 1
[Thu Dec 17 2020 20:20:14.775]  LOG      the data should be loaded

在搜索栏中输入一个字符后,输出为:

[Thu Dec 17 2020 20:23:54.892]  LOG      false 1
[Thu Dec 17 2020 20:23:54.938]  LOG      the data should be loaded
[Thu Dec 17 2020 20:23:55.526]  LOG      false 2
[Thu Dec 17 2020 20:23:55.781]  LOG      false 3
[Thu Dec 17 2020 20:23:55.807]  LOG      false 1
[Thu Dec 17 2020 20:23:55.840]  LOG      the data should be loaded
[Thu Dec 17 2020 20:23:56.294]  LOG      false 1
[Thu Dec 17 2020 20:23:56.312]  LOG      the data should be loaded

TLDR:如何确保在完全加载后访问被钩子刷新的对象?

我建议您以不同的方式解决问题。

您可以将默认值设置为 null:

,而不是将 jsonData 的默认值设置为数组
function HomeScreen() {
  const [query, setQuery] = useState("");
  const [jsonData, setJsonData] = useState(null);

  useEffect(() => {
    fetch("https://www.thecocktaildb.com/api/json/v1/1/search.php?s=" + query, {
      method: "GET",
    })
      .then((response) => response.json())
      .then((jsonD) => setJsonData(jsonD))
      .catch((error) => {
        console.error(error);
      });
  }, [query]);

  return (
    // ...
       <>{jsonData && jsonData.drinks[0].idDrink}</>
    // ...
  );
}

这样您也不需要跟踪和更新 loading 状态。

您遇到的另一种方法的问题是,您无法确定 jsonData 状态在 loading 状态更新之前已经更新。