首页 > 解决方案 > 尝试在功能组件之间传递状态但出现“未定义”错误

问题描述

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

这是我的 Header 组件:

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,
    secretAccessKey: process.env.REACT_APP_ACCESS_KEY,
  });

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

  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;

任何建议将不胜感激!

标签: javascriptreactjsdynamiccomponentsstate

解决方案


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

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

推荐阅读