Context
I'm converting a create-react-app app to nextjs. Most of my work is ensuring existing components work for SSR.
I have one component that is throwing a build error of:
Error: text.split is not a function
For the final condition of this function:
function createRender(text, type, size, paragraphs, inline, nogap, url) {
let renderObj;
if (text) {
// if text is an array, return a string of the array
if (text instanceof Array) {
text = text.join('');
}
if (type === "title") {
renderObj = <h2>{text}</h2>
} else if (paragraphs === true) {
renderObj = text.split('\n').map((paragraph, index) => {
if (paragraph !== "") {
return <p>{paragraph}</p>
}
})
} else {
renderObj = text.split('\n').map((paragraph, index) => {
if (paragraph !== "") {
return <p >{paragraph}</p>
}
})
}
}
return renderObj
}
Question
This split request (as far as I can see) is identical to that in the condition preceding it. Which doesn't throw an error.
This isn't an error occuring at runtime when something that isn't a string has been passed. This is a build error.
What am I missing that might be causing text in this one condition to throw this error? In my previous experience with javascript, I'd only get an error when running and a variable that wasn't a string had an attempted split. Here, a variable hasn't even been sent yet.
Also, why isn't it causing an error in the condition above it, with the exact same code? If I remove the final 'else' condition, I don't get the error.
Caveats
Ignore the logic in the conditions, I've removed some fluff to make this reproducible in its smallest form.
I'm using nextjs 13 and its app folder. I'm brand new to nextjs and saw this is an experimental features so I'm unsure if something exterior from this function is causing the issue.
Update 1
I've found that the error isn't thrown if I add a defined condition to the final else. As in, if I replace:
} else {
renderObj = text.split('\n').map((paragraph, index) => {
if (paragraph !== "") {
return <p >{paragraph}</p>
}
})
}
with
} else (any variable === anything) {
renderObj = text.split('\n').map((paragraph, index) => {
if (paragraph !== "") {
return <p >{paragraph}</p>
}
})
}
The condition definition is arbitrary. I can put size === 'melon' and it no longer throws an error.
I was too used to client-side-rendering and was still using the perspective that functions and variables only throw errors when building if there's bad code.
Whereas as this function is built for SSR, it's being passed actual real variables and is throwing an error in the same veign as I would have been familiar with during runtime on CSR.
So the problem was catching a bad variable that was meant to be a string but wasn't.
Related
let adminMap = new Map()
async function orionCheck(interaction, adminMap) {
const guild = await client.guilds.fetch(General.SERVER.ID)
const members = await guild.members.fetch()
var memberList = [];
members.forEach(member => memberList.push(member.user.id));
for (let i = 0; i < memberList.length; i++) {
if (members.get(memberList[i]).roles.highest.permissions.has("ADMINISTRATOR")) adminMap.set(members.get(memberList[i]).user.id, {BPM: 0, KPM: 0}) //console.log(members.get(memberList[i]).user.id)
}
var orionObjects = {
banObject: ["API/Orion Objects/OrionData.json", "Ban", "BPM", adminMap.get(interaction.user.id).BPM],
kickObject: ["API/Orion Objects/Kickbject.syrex", "Kick", "KPM", adminMap.get(interaction.user.id).KPM]
}
var objectPick = orionObjects.unknown;
if (interaction.commandName == 'ping' && General.SERVER.CHANNELS.LOGS !== "") {
objectPick = orionObjects.banObject;
if (client.orion == undefined) {
client.orion = adminMap;
console.log(client.orion.get(interaction.user.id), "client.orion made")
} else {
client.orion.set(client.orion.get(interaction.user.id).BPM, client.orion.get(interaction.user.id).BPM++)
console.log(client.orion.get(interaction.user.id))
//console.log(client.orion)
}
} else return; //ping and topic cmds are used as placeholder for ban and kick
if (interaction.commandName == 'topic' && General.SERVER.CHANNELS.LOGS !== "") {
} else return;
}
client.on('interactionCreate', async interaction => {
if (!interaction.isCommand()) return;
orionCheck(interaction, adminMap);
});
this is code for every time a command is executed, it adds 1 to your specific user on a map which is what the map is there for. the client.orion is set to the map so that it remembers it each time the command is executed and makes the map globally executable. the if statement is checking if the client.orion was already made and if its undefined it makes it. pretty simple. but the problem is, for some reason on startup, you execute the command. it makes the client.orion then you execute it again and it does the else statement since now client.orion already exists and it adds one to the array. but when you execute it a third time, it stays at one as shown
https://i.imgur.com/Uve78bx.png
This isn't a solution to your particular problem (but maybe it can provide some clues on what I was referring to in comments.)
On a Map object, set takes two parameters, the key and the value.
You have this line in your else block:
client.orion.set((interaction.user.id).BPM, client.orion.get(interaction.user.id).BPM++)
Notice that the "key" is undefined because (interaction.user.id).BPM doesn't exist.
You should have this line instead:
client.orion.set(interaction.user.id, client.orion.get(interaction.user.id).BPM++)
I thought it was strange when tested your code both ways (as undefined, and as defined) and got the same results. But whats really going on is that the set() is doing no work when the key passed to it is undefined. Instead the code in the value parameter is doing work (even though set() is not):
client.orion.get(interaction.user.id).BPM++
ALSO:
Your value parameter to set() has a logical error in that it's supposed to be an object. You are passing a integer to it. You didn't encounter what unexpected results this will create because so far your set() isn't doing work due to the undefined key.
I have this code
Cypress.Commands.add('VerifyLoginState', () => {
if(cy.contains('Login')) {
cy.get('.form-control').eq(0).type('firstfield')
cy.get('.form-control').eq(1).type('secondfield')
cy.get('.btn-login').click()
cy.wait(2500)
cy.contains('Upcoming Appointments').should('be.visible')
}
else
{
cy.contains('Appointment summary').should('be.visible')
}
})
How should I write the code so that it can pass to the condition of else, when I am authenticated in the browser and the condition of if is not valid?
In other words, I want to check if an element is present on the page, and even if it is not present, the code should not give an error and move on
Cypress yields the result of cy functions, and does not return them. So your if/else will not work as it would in traditional JavaScript. Check out this article from Cypress about conditional testing.
Something like the following should help you out:
// Get the body of the DOM
cy.get('body').then(($body) => {
// Check if the body contains the `Login` element
if ($body.contains('Login').length) {
cy.get('.form-control').eq(0).type('firstfield')
cy.get('.form-control').eq(1).type('secondfield')
cy.get('.btn-login').click()
cy.wait(2500)
cy.contains('Upcoming Appointments').should('be.visible')
} else {
cy.contains('Appointment summary').should('be.visible')
}
Another option is to use within
ref: https://docs.cypress.io/api/commands/within#Syntax
cy.contains('Login')
.within(() => {
cy.get('.form-control').eq(0).type('firstfield')
cy.get('.form-control').eq(1).type('secondfield')
cy.get('.btn-login').click()
cy.wait(2500)
cy.contains('Upcoming Appointments').should('be.visible')
})
You may find it easier to test for either/or text using jQuery :contains and multiple selectors separated by a comma
cy.get('body')
.children(':contains(Login), :contains(Appointment summary)') // only one is on the page
.invoke('text')
.then(labelText => {
if (labelText.trim() === 'Login') {
cy.get('.form-control').eq(0).type('firstfield')
... etc
} else {
cy.contains('Appointment summary').should('be.visible')
}
})
I have created this function in react native:
confirmOTP(){
console.log(this.state.otpEntry)
console.log(this.state.sixDigitauth)
if (this.state.otpEntry === this.state.sixDigitauth){
this.setState({
modalVisibility: false
})
console.log ("authenticated")
}else{
console.log ("incorrect OTP")
}
}
Although the function console logs both this.state.otpEntry and this.state.sixDigitauth and the text in them matches, I still end up getting a console log of "incorrect OTP". This means that the if statement is unable to match both states.
464042 464042 incorrect OTP
Both data types are text:
this.state = { sixDigitauth: '', otpEntry: '', }
Any idea why?
thanks in advance
It appears like you have a mismatch of datatypes, and since a triple equal sign attempts to match variables on their content, as well as their type - it returns false, hence your query fails.
You have a couple of options:
Add a + sign in front of the variables. It will convert them to a Number type:
confirmOTP(){
if (+this.state.otpEntry === +this.state.sixDigitauth) {
// do something
} else {
// do something else
}
}
Replace a === sign, with == sign. I don't recommend it, but it will technically solve the problem.
confirmOTP(){
if (this.state.otpEntry == this.state.sixDigitauth) {
// do something
} else {
// do something else
}
}
You could also make sure they're in appropriate datatypes, at the moment of updating the state:
constructor(props) {
super(props)
this.state = {
otpEntry: +props.otpEntry
sixDigitauth: +props.sixDigitauth
}
}
Make sure to catch up on some theory.
equations:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
unary plus:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus
I have a frontend app with many API requests, but it's a pain to work with error responses.
Sometimes I need to go through many nested objects like: error.response.data.email and sometimes it is error.response.data.address.province[0].
I can't predict all of the errors, and writing manual "parsers" looks like a dirty extra solution to me:
const errorsObject = err.response.data
let errors = ''
Object.keys(errorsObject).map(key => {
if (key === 'address') {
Object.keys(errorsObject.address).map(
key => (errors += `${key} : ${errorsObject.address[key]}\n`)
)
} else {
errors += `${key} : ${errorsObject[key]}\n`
}
return undefined
})
yield toast.error(errors)
Also it still doesn't cover everything.
Is there any frontend parsers for that? If not, our backend is Python(Django), maybe there is a package for backend side? Ideally I'd want to see a flat array of objects {title, message}.
Your error objects are wellformed and the base idea of parsing the errors is right from a frontend perspective.
The only issues I see in your errors response is nesting and hydration.
If you want hydrated responses you should provide to your parser the feature of retrieving correctly data and eventually map it to frontend UI.
Usually I feed my forms with an object, usually called errors where I can safely retrieve the errors related to a field by its name.
IMHO you are doing it "right", try to work on object type instead of object specific key (like "address).
This is an example of a error parser I use very often. When a very deep nesting occurs or array parsing is needed, I usually update the parser to reach the error and gain the ability to retrieve it from my UI, for example to show the error under the field, border it in red and so on:
import _ from 'lodash';
export const getErrors = (errors) => {
const validationErrors = _.get(errors, 'data.validation_messages') ? errors.data.validation_messages : {};
// Iterate over object keys
_.forOwn(validationErrors, (value, key) => {
// Simple error: { key: { errorKey: value }} - Nested Error {key: { nestedErrorKey: { errorKey: value }}
const data = validationErrors[key][Object.keys(validationErrors[key])[0]];
// Check that content of key is neither null or object (nested validation)
if (validationErrors[key] !== null && typeof data !== 'object') {
validationErrors[key] = _.values(value)[0];
} else if (validationErrors[key] !== null && typeof data === 'object') { // TODO: Recursive approach ?
// Trasform nested values so obj: { nestedKey: nestedvalue } becomes obj_nestedKey: nestedValue
_.forOwn(validationErrors[key], (nestedValue, nestedKey) => {
validationErrors[`${key}_${nestedKey}`] = _.values(nestedValue)[0];
});
}
});
return validationErrors;
};
export default getErrors;
In my previous project, every error has an error code coming in the response and on the frontend side, every error code gets mapped with error messages, which was very easy to provide multi-locale error messages. You can try that if you have control on APIs and add one more key as error_code.
I'm making a Discord bot using discord.js, and I'm starting to add JSON stuff to it, so that I can store info for individual users, in a separate file. However, I keep getting an error that says planet is not defined, at the line that says if (bot.log[mentionedGuyName].planet == undefined) {. There are some variables, modules etc. in here that haven't been declared or whatnot, but that's only because if I put all my code on here, it would be pages long. My JSON file is called log.json.
The general purpose of this code block, if it helps, is to see if the user already has a "planet". If so, the bot finds gets that value from the JSON file, and sends it to the channel. If not, then it picks a random one (code I didn't put here because of size)
I think I understand at least kind of why the error is occurring (the planet property isn't defined), but I'm not sure how to fix it. If anyone knows how to declare a JSON property or whatever is going on here, I and my server would be most grateful. Thanks in advance!
Here's my JavaScript file:
let mentionedGuy = message.mentions.members.first();
let mentionedGuyName = null;
let noMentions = message.mentions.members.first() == false ||
message.mentions.members.first() == undefined;
if (noMentions) return;
else mentionedGuyName = mentionedGuy.user.username;
if (message.content.startsWith(prefix + "planet")) {
if (message.content.length > 7) {
if (bot.log[mentionedGuyName].planet == undefined) {
bot.log[mentionedGuyName] = {
planet: jMoon
}
fs.writeFile('./log.json', JSON.stringify(bot.log, null, 4), err => {
if (err) throw err;
});
message.channel.send(targeting);
message.channel.send(coords);
} else {
message.channel.send(bot.log[mentionedGuyName].planet);
}
}
}
Change it so it checks the typeof
if(typeof <var> == 'undefined') //returns true if undefined
Noting that typeof returns a string
Source