javascript - React setState no cambia el estado de una propiedad en particular
Un antiguo desarrollador de mi empresa actual recientemente se rindió y huyó después de tener que trabajar con Typescript/React, dejándome con un montón de código roto.
Mi problema ahora es que tengo este código de TypeScript que simplemente elimina un elemento de un arreglo y cambia el estado:
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));
Mi problema es que el estado nunca actualiza mode, aunque el setState debería hacerlo. Sin importar cómo cambie las cosas, el console.log muestra 0.
Incluso poniendo un punto de interrupción en la función de renderizado, me muestra que mode es 0, cuando debería ser "gallery".
Este es el estado inicial:
this.state = {
openFiles: [],
mode: "gallery",
categories: [],
galleryState: {}
}
¿Algún consejo?
Respuesta #1
Dijiste en un comentario que un desarrollador que recientemente dejó la empresa te dejó este código. Me temo que te han dejado con un código que rompe dos de las reglas de React :-)
No puedes modificar el estado directamente, incluidos los objetos a los que hace referencia
this.state. Estás haciendo eso concurrentFiles.splice(index, 1).Estás estableciendo un nuevo estado basado en el estado existente, pero no estás utilizando la forma de callback de
setState.
Para arreglar ambos (ver comentarios):
// 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)
);
Más en los documentos del estado.
Ejemplo en vivo:
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>Nota al margen: Si no te gusta la doble página aquí:
var currentFiles = [...openFiles.slice(0, index), ...openFiles.slice(index+1)];
puedes hacerlo así en su lugar:
var currentFiles = openFiles.slice();
currentFiles.splice(index, 1);
