javascript - 推送新对象时未定义状态值
问题描述
我正在尝试将对象推{link:href}
送到我的项目中的状态。当我尝试在其中添加 href 时{link:href}
说它是未定义的:
这是我的代码:
class Download extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.inputRef = React.createRef();
this.state = {
files: []
};
}
handleClick = () => {
const node = this.inputRef.current;
const self = this;
let file;
let name;
let href;
node.addEventListener("change", function() {
const fileList = [];
for (let x = 0, xlen = this.files.length; x < xlen; x++) {
file = this.files[x];
name = file.name;
fileList.push({ name: name });
let reader = new FileReader();
reader.onload = e => {
href = e.target.result;
};
fileList.push({ link: href });
reader.readAsDataURL(file);
}
self.setState({ files: fileList });
console.log(self.state);
});
};
render() {
return (
<div className="input">
<input
onClick={this.handleClick}
id="upload-file"
className="inputName"
type="file"
multiple
ref={this.inputRef}
/>
<div>
<ul ref={this.ulRef}>
{this.state.files.map((file, index) => (
<li key={index}>
<Link to={file.link}>{file.name}</Link>
</li>
))}
</ul>
</div>
</div>
);
}
}
export default Download;
我试图{link:href}
在 reader.onload 函数之后推送的原因是因为 reader.onload 函数在 for 循环运行 x 次后被加载并且它只显示最后一项。
解决方案
首先,你不需要为此使用任何东西refs
。而且您不需要向node
(根本不需要node
)添加事件侦听器,因为您可以使用 react'sonChange
而不是onClick
. 您也不需要为此使用 a Link
。您可以只使用带有 href 的锚标签,您可以将文件数据分配给该标签。我更喜欢使用处理下载的函数,因为我觉得它给了我更多的控制权,并且不会影响浏览器的窗口或 DOM 元素。您实际上是创建一个锚标记,触发下载,然后将其删除。
您还错误地推入了元素。通过推{name: filename}
然后推入,{link: href}
您刚刚将两个对象推入您的数组,并且这两个对象都将被映射。相反,创建一个对象,并将这两个键值对添加到该对象并将该单个对象推入。在到达reader.onload
. 通过在 the 之前推一些东西,reader.onload
然后再在里面reader.onload
推一些东西,你只是把东西推了两次。
添加name
到对象。删除第一次推送,然后reader.onload
将link
值添加到同一个对象,然后将对象推送到数组中。您也不应该在 之外设置状态,reader.onload
因为这会触发重新渲染并渲染您不完整的对象,从而导致错误。仅在 中设置一次状态,reader.onload
以便在触发重新渲染时它将在列表中拥有完整的对象。
如果您希望您的文件持久存在(意味着允许将多个文件添加到您的文件列表中),而不是fileList
每次onChange
触发时设置为空数组,请将其设置为this.state.files.slice()
. 我们可以使用slice
as 创建一个新数组而不是this.state.files
直接变异。
正如您将看到的,我也删除了您的constructor
as 对于这个用例,只需使用state = {...}
就足够了。如果您更喜欢使用,constructor
您可以根据需要将其添加回来,我只是自己承担了为您节省几行代码的责任。
class Download extends React.Component {
state = {
files: []
};
handleClick = event => {
let file, name, href;
var breh = event.target;
const fileList = this.state.files.slice();
for (let x = 0, xlen = breh.files.length; x < xlen; x++) {
file = breh.files[x];
name = file.name;
var obj = {};
obj["name"] = name;
let reader = new FileReader();
reader.onload = e => {
href = e.target.result;
obj["link"] = href;
fileList.push(obj);
this.setState({ files: fileList });
};
reader.readAsDataURL(file);
}
};
download = (uri, name) => {
var link = document.createElement("a");
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
render() {
console.log(this.state);
return (
<div className="input">
<input
onChange={this.handleClick}
id="upload-file"
className="inputName"
type="file"
multiple
/>
<div>
<ul>
{this.state.files.map((file, index) => {
return (
<li
key={index}
onClick={() => {
this.download(file.link, file.name);
}}
>
{file.name}
</li>
);
})}
</ul>
</div>
<output id="list" />
</div>
);
}
}
export default Download;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
推荐阅读
- ios - 编辑时检查文本字段文本
- javascript - 如何使用 JavaScript 将伪造的图像保存到本地文件夹?
- python - Python 等效于 R 中的“library(help = PackageName)”和“?FunctionName”(即 help() 函数)
- angular - HttpClient 不返回数据
- python - 如何从存储在 gitlab repos 中的文件中提取内容
- javascript - 将图像动态添加到这个漂亮的框架中
- javascript - Email expiration tokens without usage of database and crontab deletion
- python - Kivy 相机免费资源问题
- javascript - why is the onclick event not working in javascript when the button and function reference both show the right objects?
- java - 为什么我在尝试在 Spring Boot 应用程序上配置数据库连接时获得此异常?创建名为“dataSource”的 bean 时出错