如何在 ReactJS 中的功能组件之间传递值 - 输出 [object Object]/undefined?

Posted

技术标签:

【中文标题】如何在 ReactJS 中的功能组件之间传递值 - 输出 [object Object]/undefined?【英文标题】:How to pass values between functional components in ReactJS- output [object Object]/undefined? 【发布时间】:2021-08-02 10:22:36 【问题描述】:

我无法在同一个 .js 文件中的功能组件中传递道具。我之前尝试过发布此问题,但没有任何帮助。

我想在我的第一个函数 GetMemID 中从 GET 请求中获取 member_id,并使用它在我的第二个函数 Transactions 中设置我的 useState 的 member_id

我知道我的 GET 请求正在运行,因为我能够在检查我的代码后看到数据。

到目前为止,使用我的代码,当我在 Transactions 中显示 member_id 时,我得到了“[object Object]”。

这是我目前的代码:

import React,  useEffect, useState  from 'react';
import  Redirect  from 'react-router-dom';
import moment from 'moment';
import  HomeNavBar from '../components/HomeNavBar.js';

var currentDate = moment().format("MM/DD/YYYY HH:mm:ss");

function GetMemID() 

  const [details, setDetails] = useState([]);  
  const [error, setError] = useState(null);

const options = 
  method: 'GET',
  headers: 
    'Content-type': 'application/json; charset=UTF-8',
    'Accept': 'application/json',
    'Authorization': `JWT $localStorage.getItem('token')`
  
;

useEffect(() => 
  fetch("http://########/api/members/get/", options)
  .then(response => 
    if (response.status !== 200) 
      console.log(response.status);
      setError(response);
    
    response.json().then(data => 
      setDetails(data);
    );
  );
, []);

  return (
    <div className="App">
      details.map(item => (
         <Transaction member_id=item.member_id />
      ))
    </div>
  );


function Transaction(member_id) 
//props.state
  const [error, setError] = useState(null);
  const [trans, setTrans] = useState(member_id:member_id, category:'', description:'', amount:0); 
  const [details, setDetails] = useState(id:0, mmeber_id:0, group:"", username:"");

  console.log("member_id: " + member_id);


//GET rerquest to get transaction memberID
  const options = 
    method: 'GET',
    headers: 
      'Content-type': 'application/json; charset=UTF-8',
      'Accept': 'application/json',
      'Authorization': `JWT $localStorage.getItem('token')`
    ,
  ;
  
  useEffect(() => 
    fetch("http://########/api/members/get/", options)
    .then(response => 
      if (response.status !== 200) 
        console.log(response.status);
        setError(response);
      
      response.json().then(data => 
        setDetails(data);
      );
    );
  , []);

  //POST request to API for transaction
  const optionPOST = 
    method: 'POST',
    headers: 
      'Content-type': 'application/json; charset=UTF-8',
      'Accept': 'application/json',
      'Authorization': `JWT $localStorage.getItem('token')`
    ,
    body:JSON.stringify(trans)
  

  const createTransaction = e => 
    e.preventDefault();

    fetch("http://########/api/transactions/post/", optionPOST)
    .then((response) => console.log('reponse: ' + response.json()))
    .then((message) => console.log('message: ' + message))
  

  if (error) 
    return (<Redirect to="/Signin" />);
   else
    return (
      <div className="wrapper">
        <HomeNavBar />
        <form>
          <div className="form-horizantal">
            <fieldset>
              <div className="form-group row">
                <label className="col-md-12"><p>currentDate</p></label>
              </div>
              
              <div className="form-group row">
                <label className="col-md-12">
                  <p>Member ID</p>
                  <input type="text" name="member_id" defaultValue=trans.member_id readOnly/>
                </label>
              </div>
              
              <div className="form-group row">
                <label className="col-md-12">
                  Select Category
                </label>
              </div>

              <div className="form-group row">
                <label className="col-md-12">
                  <select value=trans.category onChange=e => setTrans( ...trans, category: e.target.value ) >
                    <option value=""></option>
                    <option value="billsutilities">Bills/Utilities</option>
                    <option value="groceries">Groceries</option>
                    <option value="health">Health</option>
                    <option value="transportation">Transportation</option>
                    <option value="ehoppingentertainment">Shopping/Entertainment</option>
                    <option value="mics.">Mics.</option>
                  </select>
                </label>
              </div>

              <div className="form-group row">
                <label className="col-md-12">
                  <p>Description</p>
                  <input type="text" name="description" value=trans.description onChange=e => setTrans( ...trans, description: e.target.value ) />
                </label>
              </div>

              <div className="form-group row">
                <label className="col-md-12">
                  <p>Amount</p>
                  <input type="text" name="amount" value=trans.amount onChange=e => setTrans( ...trans, amount: e.target.value ) />
                </label>
              </div>
            </fieldset>

            <button type="submit" onClick=createTransaction>Submit</button>
          </div>
        </form>
      </div>
    );
  


export default Transaction;

【问题讨论】:

API 中的数据结构如何? &lt;Transaction member_id=item.member_id /&gt;之前记录item的值 console.log("member_id: " + member_id);function Transaction(member_id) 下面的第四行在控制台中显示什么? @kayuapi_my,它显示“member_id: undefined” @WebbH,格式为 JSON。 【参考方案1】:
const [isLoading,setIsLoading] = useState(false)
useEffect(() => 
  fetch("http://########/api/members/get/", options)
  .then(response => 
    if (response.status !== 200) 
      console.log(response.status);
      setError(response);
    
    response.json().then(data => 
      setDetails(data);
      setIsLoading(true);
    );
  );
, []);

  return (
    <div className="App">
      isLoading && details.map(item => (
         <Transaction member_id=item.member_id />
      ))
    </div>

可能的解决方案是 -> 1 ) 因为我在上面的代码示例中使用了 isLoading 状态,它最初是 false 并在从 API 加载数据时设置为 true。并有条件地渲染 Transaction 组件。 2)为了更清楚地调试它,记录状态详细信息的值(以确保我们正确获取数据),类似这样 ->

useEffect(()=>
console.log(details);
,[details])
    还要检查所有来自 API 的 JSON 数据的键是否正确。

如果对您有用,请分享您的评论。干杯!

【讨论】:

【参考方案2】:

问题

将传递的道具存储到本地状态是 React 中的反模式。您遇到的问题是Transaction 已安装并呈现之前 GetMemID 中的 GET 请求解析并更新 details 状态。

解决方案 1

只需在Transaction 组件中直接使用传递的member_id 属性即可。 trans.member_id 只使用一次并且从未更新,因此它处于状态是没有意义的。

const [trans, setTrans] = useState( category:'', description:'', amount:0 );

...

<input type="text" name="member_id" defaultValue=member_id readOnly/>

解决方案 2

如果您真的绝对必须member_id 存储到状态中,那么您需要使用依赖于道具值的useEffect 挂钩来更新状态。当传递的member_id 属性值更新时,效果回调将更新trans.member_id

const [trans, setTrans] = useState(
  member_id,
  category:'',
  description:'',
  amount:0,
);

useEffect(() => 
  setTrans(trans => (
    ...trans,
    member_id
  ));
, [member_id]);

注意:这两种解决方案都假定您正确地获取和更新父组件中的details 状态。

【讨论】:

以上是关于如何在 ReactJS 中的功能组件之间传递值 - 输出 [object Object]/undefined?的主要内容,如果未能解决你的问题,请参考以下文章

如何将服务器端渲染中的数据从节点传递给reactjs组件

如何将从数据库接收到的数据作为道具传递给 Reactjs 中的另一个组件

使用 reactjs 在组件之间传递数据

如何从 Reactjs 中的 useEffect 挂钩访问道具

如何在 Reactjs 中将数据从子组件传递到父组件? [复制]

ReactJS:在孩子和父母之间传递数据[重复]