尝试在功能组件之间传递状态但出现“未定义”错误

如何解决尝试在功能组件之间传递状态但出现“未定义”错误

我正在尝试将 2 组状态从一个组件传递到另一个组件,以便我可以在 React 的标题中列出用户的公司和名称。我知道我得到了正确的信息,因为我在将两个变量设置为我的状态之前通过控制台记录了它们,但是,当我尝试在导航栏中呈现它们时,我得到了未定义。

这是我的标题组件:

import React,{ useState } from 'react';
import { Route } from 'react-router-dom';
import { LinkContainer } from 'react-router-bootstrap';
import { Navbar,Nav,Container,NavDropdown } from 'react-bootstrap';
import SearchBox from './SearchBox';


const Header = ({ companyName,userName }) => {
  console.log(userName);
  return (
    <header className='admin-bar'>
      <Navbar bg='white' variant='secondary' expand='lg' collapSEOnSelect>
        <Container>
          <LinkContainer to='/'>
            <Navbar.Brand>{companyName}</Navbar.Brand>
          </LinkContainer>
       <NavDropdown title={userName} id='basic-nav-dropdown'>
                <NavDropdown.Item href='#action/3.1'>Profile</NavDropdown.Item>
                <NavDropdown.Item href='#action/3.2'>Insights</NavDropdown.Item>
                <NavDropdown.Item href='#action/3.3'>Settings</NavDropdown.Item>
                <NavDropdown.Divider />
                <NavDropdown.Item href='#action/3.4'>Sign Out</NavDropdown.Item>
              </NavDropdown>
            </Nav>
          </Navbar.Collapse>
        </Container>
      </Navbar>
    </header>
  );
};

export default Header;

以及我初始化状态的组件:

import Amplify,{ Auth } from 'aws-amplify';
import awsconfig from '../aws-exports';
import React,{ useState,useEffect } from 'react';
import Upload from '../components/Upload';
import BucketList from '../components/BucketList';

Amplify.configure(awsconfig);

const FileUploadScreen = () => {
  const [companyName,setCompanyName] = useState('');
  const [userSession,setUserSession] = useState('');
  const [userName,setUserName] = useState('');

  const onPageRendered = async () => {
    let user = await Auth.currentAuthenticatedUser();
    let userToken = user.getSignInUserSession().getIdToken().getJwtToken();
    setUserSession(user.getSignInUserSession());
    let base64Url = userToken.split('.')[1];
    let var1 = base64Url.replace(/-/g,'+').replace(/_/g,'/');
    let var2 = decodeURIComponent(
      atob(var1)
        .split('')
        .map(function (c) {
          return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
        })
        .join('')
    );
    let company = var2.substring(
      var2.indexOf('company') + 10,var2.indexOf('aud') - 3
    );
    console.log(company);
    setCompanyName(company);

    let userAccountName = var2.substring(
      var2.indexOf('"name":') + 8,var2.indexOf('exp') - 3
    );
    setUserName(userAccountName);
    console.log(userAccountName);
  };

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

  return (
    <>
        <div className='container main p-5'>
          <h3 className='text-center pb-1 font-weight-normal bg-white'>
            Upload Files
          </h3>
          <Upload companyName={companyName} />
          <BucketList companyName={companyName} />
        </div>
    </>
  );
};

export default FileUploadScreen;

还有我的 App.js 文件

import { useState,useEffect } from 'react';
import { browserRouter as Router,Route } from 'react-router-dom';
import { Container } from 'react-bootstrap';
import DashboardScreen from './screens/DashboardScreen';
import FileUploadScreen from './screens/FileUploadScreen';
import Sidebar from './components/Sidebar/Sidebar';
import CompanyProfileScreen from './screens/CompanyProfileScreen';
import InsightsScreen from './screens/InsightsScreen';
import WelcomeScreen from './screens/WelcomeScreen';
import Header from './components/Header';

const App = ({ companyName,userName }) => {
  const [isLoading,setIsLoading] = useState(true);

  return (
    <Router>
      <Header companyName={companyName} userName={userName} />
      <Sidebar />
      <main className=''>
        <Container>
          <Route path='/company' component={CompanyProfileScreen} />
          <Route path='/insights' component={InsightsScreen} />
          <Route path='/fileupload' component={FileUploadScreen} />
          <Route path='/landscape' component={DashboardScreen} />
          <Route path='/' component={WelcomeScreen} exact />
        </Container>
      </main>
    </Router>
  );
};

export default App;

正如我所说,我在 console.log 中得到了正确的名称(公司和用户名),但是一旦我通过它们,就没有呈现任何内容

我也在这里添加了 BucketList 组件和 Upload 组件的代码以供参考:

import { useState,useEffect } from 'react';
import AWS from 'aws-sdk';
import { ListGroup } from 'react-bootstrap';

AWS.config.update({
  accessKeyId: process.env.REACT_APP_ACCESS_ID,secretAccessKey: process.env.REACT_APP_ACCESS_KEY,region: process.env.REACT_APP_REGION,});
const s3 = new AWS.S3();

const BucketList = ({ companyName }) => {
  const [listFiles,setListFiles] = useState([]);
  const [isVisible,setIsVisible] = useState(false);

  const params = {
    Bucket: process.env.REACT_APP_BUCKET_NAME,Delimiter: '',};

  useEffect(() => {
    s3.listObjectsV2(params,(err,data) => {
      if (err) {
        console.log(err,err.stack);
      } else {
        setListFiles(data.Contents);
      }
    });
  },[]);

  // Filtering correct file names
  let files = [];
  for (let i = 0; i < listFiles.length; i++) {
    let str = listFiles[i].Key;
    if (
      str.includes('OUTPUT') &&
      str !== `${companyName}/` &&
      str !== 'OUTPUT' &&
      str.startsWith(companyName)
    ) {
      files.push(str);
    }

    for (let i = 0; i < files.length; i++) {
      if (
        files[i].endsWith(
          'vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        )
      ) {
        files[i] = files[i].replace(
          '.vnd.openxmlformats-officedocument.spreadsheetml.sheet','.xlsx'
        );
      } else if (files[i].endsWith('.vnd.ms-excel')) {
        files[i] = files[i].replace('.vnd.ms-excel','.csv');
      }
    }
  }

  // Adding dynamic class to card for scroll
  useEffect(() => {
    files.length > 3 && setIsVisible(true);
  },[files.length]);

  return (
    <div className={`card my-4 ${isVisible ? 'test' : ''}`}>
      <div className='card-header'>{companyName} Current Files</div>
      <ListGroup className='list-group'>
        {files &&
          files.map((name,index) => (
            <ListGroup.Item key={index}>
              {name.split('/').slice(2)}
            </ListGroup.Item>
          ))}
      </ListGroup>
    </div>
  );
};

export default BucketList;

import React,{ useRef,useState,Fragment,useEffect } from 'react';
import { ListGroup } from 'react-bootstrap';
import Message from './Message';
import ProgressBar from './ProgressBar';
import AWS from 'aws-sdk';

const Upload = ({ companyName }) => {
  const bucketName = process.env.REACT_APP_BUCKET_NAME;

  const fileInput = useRef();

  const [filename,setFilename] = useState('Choose File');
  const [message,setMessage] = useState('');
  const [fileInfos,setFileInfos] = useState([]);
  const [progress,setProgress] = useState(0);
  const [showProgressBar,setShowProgressBar] = useState(false);
  const [isScroll,setIsScroll] = useState(false);

  const selectFile = (e) => {
    setFilename(e.target.files[0].name);
  };

  const handleClick = (event) => {
    event.preventDefault();
    let newArr = fileInput.current.files;
    for (let i = 0; i < newArr.length; i++) {
      handleUpload(newArr[i]);
    }
  };

  AWS.config.update({
    accessKeyId: process.env.REACT_APP_ACCESS_ID,});

  const myBucket = new AWS.S3({
    params: {
      Bucket: `${bucketName}/${companyName}`,},});

  const handleUpload = (file) => {
    const params = {
      ACL: 'public-read',Key: file.name,ContentType: file.type,Body: file,};

    let newFileName = file.name;

    myBucket
      .putObject(params)
      .on('httpUploadProgress',(evt) => {
        setProgress(Math.round((evt.loaded / evt.total) * 100));
        setFileInfos([newFileName,...fileInfos]);
        setMessage('File uploaded');
      })
      .send((err) => {
        if (err) {
          console.log(err);
          setShowProgressBar(false);
          setMessage('Could not upload file');
        }
      });
  };

  useEffect(() => {
    fileInfos.length >= 2 && setIsScroll(true);
  },[fileInfos.length]);

  if (progress === 100) {
    setTimeout(() => {
      setProgress(0);
      setShowProgressBar(false);
      setMessage('');
    },3000);
  }

  return (
    <Fragment>
      <form className='bg-white my-4' onSubmit={handleClick}>
        {message ? <Message msg={message} /> : null}
        <div className='custom-file mb-2'>
          <input
            type='file'
            onChange={selectFile}
            multiple
            ref={fileInput}
            id='customFile'
            className='custom-file-input'
          />

          <label className='custom-file-label' htmlFor='customFile'>
            {filename}
          </label>
        </div>
        {showProgressBar ? <ProgressBar percentage={progress} /> : null}

        <input
          type='submit'
          value='Upload'
          className='btn btn-primary btn-block mt-3'
          disabled={filename === 'Choose File'}
          onClick={() => setShowProgressBar(true)}
        />

        <br />

        <div className={`card ${isScroll ? 'test' : ''}`}>
          <div className='card-header'>Recently Added</div>
          <ListGroup className='list-group'>
            {fileInfos &&
              fileInfos.map((file,index) => (
                <ListGroup.Item key={index}>{file}</ListGroup.Item>
              ))}
          </ListGroup>
        </div>
      </form>
    </Fragment>
  );
};

export default Upload;

任何建议将不胜感激!

解决方法

您必须将以下依赖项添加到 useEffect 钩子中,以便在您获取公司名称和用户名时更新:

useEffect(() => {
    onPageRendered();
  },[companyName,userName]);
,

为什么会这样

  1. useState 钩子中的 Setter 方法是一个异步函数。
  2. 你在 useEffect Hook 中调用的函数也是一个异步函数
  3. 现在,由于您没有在 useEffect Hook 中设置任何依赖项,因此在程序加载的初始化过程中,会在 wepApi(事件循环)中发送异步函数。
  4. 由于 sate 的初始值是一个空字符串并且程序最初运行时不关心 Async 函数,因此您在 jsx 中只剩下空值。

如何解决

  1. 只需在 useEffect 依赖数组中传递依赖

    useEffect(() => { onPageRendered(); },[公司名,用户名]);

  2. 此外,您可以在 jsx 中添加条件渲染以检查该值是否存在。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?