[英]React setState not changing state of particular property
An old dev at my current company recently put his tail between his legs and fled after having to do Typescript/React, leaving me when a bunch of broken code. 我现在公司的一个旧开发人员最近把他的尾巴放在他的腿之间,并且在做了打字稿/反应后逃离,留下了一堆破碎的代码。
My problem now is that I have this TypeScript code that simply removes an item from an array and changes the state: 我现在的问题是我有这个TypeScript代码,只是从数组中删除一个项目并更改状态:
var currentFiles = this.state.openFiles;
var index = this.state.openFiles.findIndex((f: IFileModel) => f.fileId == fileId)
currentFiles.splice(index, 1);
this.setState({
mode: "gallery",
openFiles: currentFiles
}, () => console.log(this.state.mode));
My problem is that the state never updates mode
, even though the setState should do so. 我的问题是状态永远不会更新
mode
,即使setState 应该这样做。 Regardless of how I change things up, the console.log
shows is 0
. 无论我如何改变,
console.log
显示为0
。
Even putting a breakpoint in the render function, shows me that mode
is 0
, where it should be "gallery"
. 即使在渲染函数中放置断点,也会向我显示
mode
为0
,它应该是"gallery"
。
This is the initial state: 这是初始状态:
this.state = {
openFiles: [],
mode: "gallery",
categories: [],
galleryState: {}
}
Any advice? 有什么建议?
You said in a comment that you've been left this code by a dev who recently left the company. 您在评论中说,您最近离开了该公司的开发人员已离开此代码。 I'm afraid they've left you with code breaking two of React's rules: :-)
我担心他们给你的代码违反了React的两条规则:--)
You cannot directly modify state, including objects that this.state
refers to. 您无法直接修改状态,包括
this.state
引用的对象。 You're doing that with currentFiles.splice(index, 1)
. 你正在使用
currentFiles.splice(index, 1)
。
You're setting new state based on existing state, but not using the callback form of setState
. 您正在基于现有状态设置新状态,但不使用
setState
的回调形式。
To fix both (see comments): 修复两者(见评论):
// Use the callback form that receives the up-to-date state as a parameter.
this.setState(
({openFiles}) => {
var index = openFiles.findIndex((f: IFileModel) => f.fileId == fileId)
// (Do you need an `if (index !== -1)` check here?)
// Create a *new* array without the entry
var currentFiles = [...openFiles.slice(0, index), ...openFiles.slice(index+1)];
// Return the new state
return {
mode: "gallery",
openFiles: currentFiles
};
},
() => console.log(this.state.mode)
);
More in the state docs . 更多在州文件 。
Live Example: 实例:
class Example extends React.Component { constructor(...args) { super(...args); this.removeFileOnClick = this.removeFileOnClick.bind(this); this.state = { mode: "main", openFiles: [ {fileId: 1, name: "File 1"}, {fileId: 2, name: "File 2"}, {fileId: 3, name: "File 3"}, {fileId: 4, name: "File 4"}, {fileId: 5, name: "File 5"} ] }; } removeFileOnClick(e) { const fileId = e.currentTarget.getAttribute("data-id"); this.setState( ({openFiles}) => { var index = openFiles.findIndex((f) => f.fileId == fileId) // (Do you need an `if (index !== -1)` check here?) // Create a *new* array without the entry var currentFiles = [...openFiles.slice(0, index), ...openFiles.slice(index+1)]; // Return the new state return { mode: "gallery", openFiles: currentFiles }; }, () => console.log(this.state.mode) ); } render() { return ( <div> Mode: {this.state.mode} <div> OpenFiles ({this.state.openFiles.length}): <div>{this.state.openFiles.map(file => <div><button data-id={file.fileId} onClick={this.removeFileOnClick}>X</button>{file.name}</div> )}</div> </div> </div> ); } } ReactDOM.render( <Example />, document.getElementById("root") );
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>
Side note: If you don't like the double spread here: 旁注:如果你不喜欢这里的双重传播:
var currentFiles = [...openFiles.slice(0, index), ...openFiles.slice(index+1)];
you can do it like this instead: 你可以这样做:
var currentFiles = openFiles.slice();
currentFiles.splice(index, 1);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.