Estoy tratando de implementar una actualización de estado de encadenamiento opcional simple. Lo que quiero es que los elementos SOLO se cambien SI el elemento está definido/existe; si no está/no está definido, quiero que el elemento mantenga el estado anterior (por ejemplo, el ID de usuario debe permanecer = 2 si no se actualiza).
Para probar esto creé un objeto con tres variables:
const userObj = { firstName: "", lastName: "", userID: 2, };Luego creé una función para actualizar el estado:
const updateState = (item) => { return { userObj.firstName = item?.firstName, userObj.lastName = item?.lastName, userObj.userID = item?.userID, }; };Finalmente, paso el elemento que contiene solo un elemento para actualizar (firstName) y llamo a la función:
const item = { firstName: "None", }; console.log(updateState(item));La salida:
userObj.firstName = item?.firstName, ^ SyntaxError: Unexpected token '.' Pero cuando paso el mouse sobre userObj puedo ver sus propiedades:
Obtiene este error porque lo que está tratando de devolver es un objeto con puntos en sus claves.
Está mezclando asignación y creación de objetos. Además item?.firstName solo ayuda en el caso de que item sea nulo o indefinido en el sentido de que falla rápidamente en lugar de generar una excepción porque no puede acceder a null.firstName .
Para este tipo de valor predeterminado, tendría que hacer algo como typeof item.firstName === 'string' ? item.firstName : userObj.firstName .
Para juntar todo:
const func = (value, fallback) => ( typeof value === typeof fallback ? value : fallback ); const updateState = (item) => { userObj.firstName = func(item?.firstName, item.firstName); userObj.lastName = func(item?.lastName, item.lastName); userObj.userID = func(item?.userID, item.userId); return userObj; }; Sin embargo, tenga en cuenta que esta función userObj .
Editar: default fue una mala elección de nombre.
Puede hacerlo de esta manera, utilizando la desestructuración de objetos de JavaScript
const updateState = (item) => { return { ...userObj, ...item, }; };por lo que solo actualizará la clave y el valor que se pasó, espero que la pregunta no esté en mecanografiado
Puede usar la fusión nula junto con el encadenamiento opcional:
const updateState = item => ({ userObj.firstName = item?.firstName ?? userObj.firstName , userObj.lastName = item?.lastName ?? userObj.lastName , userObj.userID = item?.userID ?? userObj.userId , });Podrías usar el operador de propagación :
const updateState = item => { userObj = { ...userObj, ...item }; return userObj; } O puede usar la función defaults() de lodash :
const _ = require('lodash'); const updateState = item => { userObj = _.defaults(userObj, item) return userObj; }O... si realmente desea mutar el objeto de estado, en lugar de crear uno nuevo y reemplazarlo, haga el suyo propio, similar:
const updateState = item => { for (const key in item ) { const hasValue = key != null && key != undefined && key != NaN ; if ( hasValue ) { userObj[prop] = item[prop]; } } }Hay, como dicen, más de una forma de despellejar a un gato.
[ Editado: Agregar explicación del operador de propagación ]
El operador de propagación,
const obj = { ...obj1, ...obj2, . . . , ...objN };es algo similar a llamar a una función como esta:
const obj = mergeObjects( obj1, obj2, . . ., objN ); donde mergeObjects() se define como:
function mergeObjects(...objects) { const mergedObject = {}; for (const obj of objects ) { for (const key in obj ) { mergedObject[key] = item[key]; } } return mergedObject; } O tal vez se podría hacer una mejor explicación usando Object.assign() . Se podría decir que una expresión como:
const obj = { prop1: 'a' , prop2: 'b' , ...obj1 , prop3: 'c' , prop4: 'd' , ...obj2 , prop5: 'e' , prop6: 'f' , ...obj3 , }es el equivalente de esto:
const obj = Object.assign( {}, { prop1: 'a' , prop2: 'b' , }, obj1 , { prop3: 'c' , prop4: 'd' , } , obj2 , { prop5: 'e' , prop6: 'f' , } , obj3 , );