【问题标题】:Javascript - React Data from Async fetching is undefined using 'useEffect()' and 'useState'Javascript - 使用“useEffect()”和“useState”未定义来自异步获取的反应数据
【发布时间】:2021-02-07 01:20:07
【问题描述】:

我对反应很陌生。我正在尝试从 API 获取一些数据。我想获取用户。但是,稍后当我想处理用户数据时,用户未定义。我对异步函数的工作原理感到困惑。

我想获取一个用户,然后将用户传递给UserInfo 组件。在UserInfo 组件中,我想在将数据显示在网站上之前对其进行处理。我收到“TypeError: Cannot read property 'split' of undefined”的错误。

非常感谢任何帮助!

App.js

function App() {
  const classes = useStyles()

  const [user, setUser] = useState({})
  const [posts, setPosts] = useState([])
  const [userList, setUserList] = useState([])

  useEffect(() => {
    const getUser = async () => {
      const userFromServer = await fetchUser()
      if (userFromServer) {
        setUser(userFromServer)
      } else {
        console.log("error")
      }
    }

    const getPosts = async () => {
      const postsFromServer = await fetchPosts()
      setPosts(postsFromServer)
    }

    const getUserList = async () => {
      const userListFromServer = await fetchUserList()
      setUserList(userListFromServer)
    }

    getUser()
    getPosts()
    getUserList()
  }, [])

  // Fetch user 
  const fetchUser = async () => {
    const res = await fetch('https://jsonplaceholder.typicode.com/users/1')
    const data = await res.json()

    return data
  }

  // Fetch posts
  const fetchPosts = async () => {
    const res = await fetch('https://jsonplaceholder.typicode.com/posts?userId=1')
    const data = await res.json()

    return data
  }

  // Fetch list of users
  const fetchUserList = async () => {
    const res = await fetch('https://jsonplaceholder.typicode.com/users/')
    const data = await res.json()

    return data
  }

  return (
    <div>
      <Box className={classes.headerImage}>
        <UserMenu userList = {userList} />
      </Box>
      <Container maxWidth="lg" className={classes.userContainer}>
        <UserInfo user = {user} />
      </Container>
      <Container maxWidth="lg" className={classes.blogsContainer}>
        <PostList name = {user.name} posts = {posts} />
      </Container>
    </div>
  );
} 

export default App;

用户信息.js

    const classes = useStyles()

    console.log(user.phone)
    const phoneStr = user.phone.split(" ")[0]

    // var companyStr = user.company.bs.replaceAll(" ", "· ")

    // const addressDic = user.address
    // const addressStr = addressDic.street + " " + addressDic.suite + " " + addressDic.city + " " +addressDic.zipcode

    return (
        <div>
            <h2>{user.name}</h2>
            <Paper elevation={0} className={classes.paper}>
                <Grid container>
                    <Grid item xs={1}>
                        <img className={classes.icon} src={phoneIcon} />
                    </Grid>
                    <Grid item className={classes.gridText} xs={11}>
                        {phoneStr}
                    </Grid>
                    <Grid xs={1}>
                        <img className={classes.icon} src={categoryIcon} />
                    </Grid>
                    <Grid item className={classes.gridText} xs={11}>
                        
                    </Grid>
                    <Grid item xs={1}>
                        <img className={classes.icon} src={shopIcon} />    
                    </Grid>
                    <Grid item className={classes.gridText} xs={11}>
                        
                    </Grid>
                </Grid>
            </Paper>
        </div>
    )
}

export default UserInfo

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    这是因为用户信息并不总是可用的。当您等待获取用户数据时,组件树会继续呈现。 user.phone 将未定义,undefined.split() 会导致错误。

    您可以通过在调用 split 之前首先检查 user.phone 的存在来解决此问题。

    user.phone && user.phone.split(" ")[0]
    

    但是,这只会解决一行,您需要对 User 组件中的每个查找都执行此操作,这不是很好。最好将用户的默认状态设置为null。

    const [user, setUser] = useState(null)
    

    然后只在用户不为空时渲染用户组件

          <Container maxWidth="lg" className={classes.userContainer}>
            { user ? <UserInfo user = {user} /> : 'loading...'} 
          </Container>
    

    【讨论】:

    • 非常感谢!请问这段代码背后的过程是什么?是否会自动响应并不断检查获取的用户是否存在,并且仅在数据可用时才呈现组件?这样我就不必编写自己的循环来检查它何时可用?我也想做一个加载页面,但我想我应该先了解它是如何工作的。
    • React 会为你处理这一切。每当状态更改时,react 都会根据该新状态重新渲染并适当地显示组件。当然,您可以用自定义组件替换加载字符串。
    【解决方案2】:

    首先,在Promise.all 中获取您的呼叫,这样您就可以确保在设置状态之前正确执行您的所有呼叫,在您的useEffect 中:

     useEffect(() => {
       const getUser = async () => await fetchUser();
       const getPosts = async () => await fetchPosts();
       const getUserList = async () => await fetchUserList();
    
       (async () => {
         try {
           const [response1, response2, response3] = await Promise.all(getUser(), getPosts(), getUserList());
           userFromServer && setUser(response1);
           setPosts(response2);
           setUserList(response3);
         } catch (err) {
           throw new Error(`Something went wrong: ${err}`);
         }
       })();
     }, []);
    

    然后,在您返回时,等到设置用户数据,例如:

    {user?.phone && <UserInfo user={user} />}
    

    【讨论】:

      猜你喜欢
      • 2020-10-19
      • 1970-01-01
      • 2021-06-06
      • 2016-06-28
      • 2021-12-20
      • 2022-08-11
      • 1970-01-01
      • 2022-12-05
      • 1970-01-01
      相关资源
      最近更新 更多