如何在 <Fragment> React 中使用来自 Promise 的数据

How to use data from a Promise in <Fragment> React

我需要在我的 React 应用程序中获取当前用户的名称,所以我将数据从 action/auth.js 发送到 Navbar.js,在导航栏中我得到了一个 Promise,所以然后我用它来获取数据。我设法 console.log 数据。但是我不能使用它来向用户展示它。 这是我用于发送数据的 auth.js 函数:

export const get_user_data = () => async dispatch => {
    if (localStorage.getItem('access')) {
    const config = {
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `JWT ${localStorage.getItem('access')}`,
                'Accept': 'application/json'
            }
        };
         try {
            const res = await axios.get(`${process.env.REACT_APP_API_URL}/auth/users/me/`, config);
            let name = res.data.first_name +" "+ res.data.last_name;
            return name;


        } catch (err) {

            return err;
        }
    } else {
        return "else accesss"
    }
};

这是我的 Navebar.js 我试图显示数据的地方:

import React, { Fragment } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { logout, get_user_data } from '../actions/auth';


const Navbar = ({ get_user_data,logout, isAuthenticated}) => {

    console.log("get_user_data", get_user_data().then(res=>{
    console.log("res", res)}));

    const get_name = () => (
    get_user_data().then(res=> {return res})
    );

    const guestLinks = () => (
        <Fragment>
            <li className='nav-item'>
                <Link className='nav-link' to='/login'>לכניסה</Link>
            </li>
            <li className='nav-item'>
                <Link className='nav-link' to='/signup'>להרשמה</Link>
            </li>
        </Fragment>
    );

    const authLinks = () => (

    <Fragment>
        <li className='nav-item'>
            <a className='nav-link' href='#!' onClick={logout}>ליציאה</a>
        </li>
        <li className='nav-item'>
                <Link className='nav-link' to='/homepage'>העסק שלי</Link>
        </li>
        {<li className='nav-item'>
            <Link className='nav-link'>ברוך הבא {get_name()}</Link>
        </li>}


    </Fragment>
    );

    return (

            <nav className='navbar navbar-expand-lg navbar-light bg-light' lang="he" dir="rtl">
                <Link className='navbar-brand' to='/'>החשמלאי</Link>
                <button
                    className='navbar-toggler'
                    type='button'
                    data-toggle='collapse'
                    data-target='#navbarNav'
                    aria-controls='navbarNav'
                    aria-expanded='false'
                    aria-label='Toggle navigation'
                >
                    <span className='navbar-toggler-icon'></span>
                </button>
                <div className='collapse navbar-collapse' id='navbarNav'>
                    <ul className='navbar-nav'>
                        <li className='nav-item active'>
                            <Link className='nav-link' to='/'>עמוד הבית <span className='sr-only'>(current)</span></Link>
                        </li>

                        {isAuthenticated ? authLinks() : guestLinks()}
                    </ul>
                </div>
            </nav>
    );
};

const mapStateToProps = state => ({
    isAuthenticated: state.auth.isAuthenticated
    });

export default connect(mapStateToProps, { logout, get_user_data })(Navbar);

我使用 get_name() 函数从承诺中解析数据,但我仍然收到承诺错误。

React 错误:

react-dom.development.js:13231 Uncaught Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.

谢谢!

我看到你正在使用 redux 和 connect 连接到你的状态。 如果您在此之前使用过 hooks 可能会更短更清晰:

const Navbar = () => {
  const dispatch = useDispatch()

  // Instead of using connect to get state, you can use the hook useSelector:
  const isAuthenticated = useSelector(state => state.auth.isAuthenticated);
  // No user to begin with
  const [user, setUser] = useState(null);

  // This will run once when the navbar renders for the first time
  useEffect(() => {
    get_user_data().then(fetchedUser => setUser(fetchedUser))
  }, [])

  function dispatchSomeAction() {
    // Fire of action to redux
    dispatch({ type: "logout" })
  }

  return (
    <Fragment>
      {user !== null && (<div>{user.name}</div>)}
      <div>{isAuthenticated ? <p>Authenticated!</p> : <p>Not Authenticated</p>}</div>
      <button onClick={dispatchSomeAction} >I will dispatch a action to redux</button>
    </Fragment>
  );
};

如果您使用的是 redux,还请阅读 redux-thunk。它允许您执行异步操作,例如 API 调用并将返回值存储在您的状态中 :)

分析

您的行为是因为您试图显示 Promise。在显示之前,您需要等待 Promise 被解析。在这里,我将使用 useStateuseEffect 挂钩来实现我所说的行为。

解决方案

首先,您需要一个状态来保持您的 userData。从您在 get_user_data 函数中的代码,我们假设我们正在谈论的 data 是用户名。此状态的默认值为空字符串。

const [name, setName] = useState('');

然后,我将创建一个 useEffect 挂钩以使用您的 get_user_data 函数填充新创建的 name 状态:

useEffect(() => {
  get_user_data().then((data) => {
    setName(data);
  });
}, []);

此挂钩将获取数据并在获取完成后设置 name 状态。

然后我们需要在任何需要的地方使用这个 name 状态。该组件的行为是当我们获取用户名时它会显示 '',但是一旦数据可用,UI 就会显示它。把它们放在一起,我们有:

import React, { Fragment, useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { logout, get_user_data } from '../actions/auth';


const Navbar = ({ get_user_data,logout, isAuthenticated}) => {
    const [name, setName] = useState('');

    useEffect(() => {
      get_user_data().then((data) => {
        setName(data);
      });
    }, []);

    const guestLinks = () => (
        <Fragment>
            <li className='nav-item'>
                <Link className='nav-link' to='/login'>לכניסה</Link>
            </li>
            <li className='nav-item'>
                <Link className='nav-link' to='/signup'>להרשמה</Link>
            </li>
        </Fragment>
    );

    const authLinks = () => (

    <Fragment>
        <li className='nav-item'>
            <a className='nav-link' href='#!' onClick={logout}>ליציאה</a>
        </li>
        <li className='nav-item'>
                <Link className='nav-link' to='/homepage'>העסק שלי</Link>
        </li>
        {<li className='nav-item'>
            <Link className='nav-link'>ברוך הבא {get_name()}</Link>
        </li>}


    </Fragment>
    );

    return (

            <nav className='navbar navbar-expand-lg navbar-light bg-light' lang="he" dir="rtl">
                <Link className='navbar-brand' to='/'>החשמלאי</Link>
                <button
                    className='navbar-toggler'
                    type='button'
                    data-toggle='collapse'
                    data-target='#navbarNav'
                    aria-controls='navbarNav'
                    aria-expanded='false'
                    aria-label='Toggle navigation'
                >
                    <span className='navbar-toggler-icon'></span>
                </button>
                <div className='collapse navbar-collapse' id='navbarNav'>
                    <ul className='navbar-nav'>
                        <li className='nav-item active'>
                            <Link className='nav-link' to='/'>עמוד הבית <span className='sr-only'>(current)</span></Link>
                        </li>

                        {isAuthenticated ? authLinks() : guestLinks()}
                    </ul>
                </div>
            </nav>
    );
};

const mapStateToProps = state => ({
    isAuthenticated: state.auth.isAuthenticated
});

export default connect(mapStateToProps, { logout, get_user_data })(Navbar);