如何解决尝试在功能组件之间传递状态但出现“未定义”错误
我正在尝试将 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]);
,
为什么会这样
- useState 钩子中的 Setter 方法是一个异步函数。
- 你在 useEffect Hook 中调用的函数也是一个异步函数
- 现在,由于您没有在 useEffect Hook 中设置任何依赖项,因此在程序加载的初始化过程中,会在 wepApi(事件循环)中发送异步函数。
- 由于 sate 的初始值是一个空字符串并且程序最初运行时不关心 Async 函数,因此您在 jsx 中只剩下空值。
如何解决
-
只需在 useEffect 依赖数组中传递依赖
useEffect(() => { onPageRendered(); },[公司名,用户名]);
-
此外,您可以在 jsx 中添加条件渲染以检查该值是否存在。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。