react-navigation navigate in array unexpected tokens ?
const { navigate } = this.props.navigation;
navigate('Properties', {
list.map((item) => {
["module"+item.id]:this.state["module"+item.id]
})
});
Returns error:
Unexpected token, expected ";"
First, when you provide a single expression arrow function that returns an object, you have to wrap that object with parentheses, otherwise the interpreter thinks the braces are a block, and not the object root.
list.map((item) => ({
["module"+item.id]: this.state["module"+item.id]
}))
Second, it looks like you're trying to create the params object from a list of values.
But the result of the map you wrote, is a list of objects, not an object.
One of the ways to create that object is by using the reduce function:
list.reduce((accumulator, current) => (Object.assign(accumulator, {["module"+current.id]: this.state["module"+current.id]})), {});
But perhaps a more performant and simpler way would be to just do it with a local side effect:
function prepareParams(list) {
let result = {};
list.forEach(item => result["module"+item.id] = this.state["module"+item.id]);
return result;
}
And then in your navigate:
navigate('Properties', prepareParams(list));
Navigation params have to be in object format so you have to add a key
navigate('Properties', { someKey: list.map((item) => { ... }) });
Related
I am trying to write a custom cypress command but the code in my then portion is not executing. any help will be appreciated thanks
my command looks similar to this:
Cypress.Commands.add("ex", () => {
const links=[]
cy.get("*[class='link post']").each((link)=>{
links.push(link.href)
}).then(() => {
var i=0;
while (links[i]) {
cy.visit(link)
i++
}
})
})
There are a few things going on here we should step through.
In your each() block, link.href will return an undefined value, so when you get to your then method, you have no links in your array to visit. Instead of links.push(link.href), try links.push(links.attr('href') to grab the value of your href attribute.
In your then method, your while loop isn't the most efficient way of looping through your array (and it will most likely error out for you with an undefined value). You should instead use a .forEach(), like so:
links.forEach((link)=>{
cy.visit(link)
)
If you do not need to persist the links array, then your entire command can be majorly simplified:
Cypress.Commands.add("ex", () => {
cy.get("*[class='link post']")
.then((links) => {
links.each((link)=>{
cy.visit(link.attr('href'))
})
})
});
To add to Kerry's answer,
The parameter given to a .then() callback is a jQuery object, containing one or more elements found by cy.get(...)
To iterate over the elements, you need to de-structure the jQuery object with the spread operator,
Cypress.Commands.add("visitLinks", () => {
cy.get("*[class='link post']")
.then($links => { // $links is a jQuery wrapper
[...$links].forEach(link => { // link is a raw element
const url = link.getAttribute('href') // apply DOM method
cy.visit(url)
})
})
});
or if you want to use the Cypress iterator .each() instead of .then(),
Cypress.Commands.add("visitLinks", () => {
cy.get("*[class='link post']")
.each($link => { // jQuery wrapped element
const href = $link.attr('href') // apply jQuery method
cy.visit(href)
})
});
However
It's going to break.
cy.visit() navigates the page, which changes the DOM in the page, so on the 2nd iteration of .each(), Cypress sees things have changed and crashes (probably a "detached element" error).
You should separate the query (grabbing the links) from the action (visiting them).
Cypress.Commands.add("getLinks", () => {
const found = [];
cy.get("*[class='link post']")
.each($link => { // jQuery wrapped element
const href = $link.attr('href') // apply jQuery method
found.push(href)
})
.then(() => found) // wait until iteration finishes
// then return the array of links
});
Use it like this
cy.getLinks()
.then(links => {
links.forEach(link => cy.visit(link))
})
The first call (Storage.list('s3 bucket path')) returns a list of keys.
For each key, I make a second call (Storage.get('key')) that returns a url
Inside the first AND second API call I console.log and get the correct data I need for each.
this.setState works perfectly inside the first API call, but it doesn't inside the second one.
My code is:
state = { keyItems: [], urlItems: [] }
componentDidMount() {
Storage.list('')
.then(keyItems => {
console.log("keyItems: ", keyItems)
this.setState({ keyItems: keyItems })
/*for each photo key in the folder..*/
keyItems.forEach(function(keyItem) {
/*get the URL*/
Storage.get(keyItem.key)
.then(urlItem => {
console.log("urlItem: ", urlItem)
/*add URL item to state*/
/*ANY CALL TO this.setState HERE DOESN'T WORK, i've tried
even simple tests*/
this.setState(prevState => ({ urlItems:[...prevState.urlItems, { key: keyItem.key, source: urlItem } ]}))
})
.catch(err => {
console.log("error fetching photo URL", err)
})
})
})
.catch(err => {
console.log("error fetching photos keys", err)
})
}
Console:
I've tried making the calls from arrow functions outside the componentDidMount but still can't access the this.setState
Thanks!
The value of this is getting lost inside the .then
You could try this
Set this to a variable
Use that variable instead of this
Here it in code
componentDidMount () {
const that = this;
// now call setState like this
that.setState(...)
}
You can read more about it at the link below, but I’ve put the general gist of it here.
this is always the object the method is called on. However, when
passing the method to then(), you are not calling it! The method
will be stored somewhere and called from there later.
Why is 'this' undefined inside class method when using promises?
I am creating react-native app. I have an array and want to use value outside the looping. I have declared value in this.state={current_cat_id:'',} I have tried it in componentWillMount like:
componentWillMount() {
var ids = [];
this.props.data.map((dataImage,Index) => {
dataImage['main-head'].map((subchild,Index2) => {
ids.push(subchild['path'])
})
})
this.setState({current_cat_id: ids})
}
its returning blank page. is this right approch
it should work for you. try this:-
componentWillMount() {
var ids = [];
this.props.data.map((dataImage) => {
dataImage['main-head'] != undefined && dataImage['main-head'].map((subchild) => {
ids.push(subchild['path'])
})
})
this.setState({current_cat_id: ids})
}
componentWillMount is called before the render method is executed. It is important to note that setting the state in this phase will not trigger a re-rendering. Avoid introducing any side-effects or subscriptions in this method. Use componentDidMount() instead.
I have two async requests, want to write a epic do the job like promise.all()
const fetchData1 = () => (action$: ActionsObservable<any>, store: any) => (
ajax.getJSON('../../mockData/promiseAll/data1.json').map((data: any) => {
return requestData1Success(data);
})
);
const fetchData2 = () => (action$: ActionsObservable<any>, store: any) => (
ajax.getJSON('../../mockData/promiseAll/data2.json').map((data: any) => {
return requestData2Success(data);
})
)
const requestAllDataEpic = (action$: ActionsObservable<any>, store: any) => {
return action$.ofType(t.REQUEST_ALL_DATA)
.map((action) => action.payload)
.switchMap((names: string[]) => {
console.log(names);
return Observable.forkJoin([
fetchData1()(action$, store),
fetchData2()(action$, store)
])
.map((results: any[]) => {
const [action1, action2] = results;
requestData1Success(action1);
requestData2Success(action2);
});
});
};
But when I dispatch the action, the console give me an error:
Uncaught TypeError: Cannot read property 'type' of undefined
I think the reason is I do not give the middleware an action object, but undefined.
How can I do this correctly?
In the provided example, you are not actually returning your two actions, you're returning nothing:
.map((results: any[]) => {
const [action1, action2] = results;
// v----- not returning either of these
requestData1Success(action1);
requestData2Success(action2);
});
map can't used to emit two actions sequentially because it's 1:1 not 1:many (mergeMap, switchMap, concatMap, etc are 1:many). However, in your example you are already converting the responses to the actions inside your fetchData helpers--doing it again would wrap an action inside another action, not what you want. This looks like a bug when you were refactoring.
Other than that, it's actually not clear what you intended to do. If you have further questions you'll need to describe what you want you'd like to achieve.
I'm using Nightwatch with mocha.
I try to get an element's text from the page object. When trying to compare the received text to another text I receive an error "AssertionError: expected undefined to equal 'Text'".
This is the Page Object function:
const Commands = {
getInstanceLabel() {
this.getText('.DropdownSelect__label', (result) => {
return result.value;
});
}
}
And this is the Test code:
it('Should sort the collection in ascending order by default', (client) => {
const labelText = client.page.instanceCollectionPage().getInstanceLabel();
expect(labelText).to.equal('Text');
});
Why is this showing undefined?
The thing is that you are using arrow functions, and as mentioned in mdn:
An arrow function expression has a shorter syntax compared to function
expressions and does not bind its own this, arguments, super, or
new.target.
You can fix it in two different ways:
using function:
e.g. (you can use this)
it('Should launch', function (browser) {
const url = browser.launchUrl;
browser.url(url).waitForElementVisible('body', 1000);
browser.getText('#txtWelcome', function (result) {
this.verify.equal(result.value, 'Welcome');
});
});
using browser:
e.g. (you need to access the browser object direcly)
it('Should launch', (browser) => {
const url = browser.launchUrl;
browser.url(url).waitForElementVisible('body', 1000);
browser.getText('#txtWelcome', (result) => {
browser.verify.equal(result.value, 'Welcome');
});
});
Those are just examples on how to use this, I can not provide more details on your issue because you don't show what InstanceCollection does.