I have an action, that gets a payload of .times. I want to loop something this many times, I did this:
function upAsyncEpic(action$: Observable<Action>, state$: StateObservable<State>): Observable<Action> {
return action$.pipe(
ofType(UP_ASYNC),
delay(1000),
mapTo(up())
);
}
This will not loop it will only happen once. I want it to loop the "delay" then "mapTo" action.times times. I tried this:
return action$.pipe(
ofType(UP_ASYNC),
repeat(action => action.times),
delay(1000),
mapTo(up())
);
But this did not work. Super brand new to redux-observables, just learning.
Basically what I want is if someone dispatches action { type: 'UP_ASYNC', times: 5 } what should happen is this:
delay(1000),
mapTo(up())
delay(1000),
mapTo(up())
delay(1000),
mapTo(up())
delay(1000),
mapTo(up())
delay(1000),
mapTo(up())
Problem: repeat() takes an integer as an argument for the count to repeat.
Signature:
repeat(count: number): Observable.
Documentation.
Example from learnrxjs
Your example will look something like this:
function upAsyncEpic(
action$: Observable<Action>,
state$: StateObservable<State>
): Observable<Action> {
let count = 0;
const source = action$.pipe(
ofType(UP_ASYNC),
map(({ times }) => {
count = times;
}),
delay(1000),
mapTo(up())
);
return source.pipe(repeat(count));
}
Related
I want to use dataloader loadMany function in nestjs. Can any help me to use it properly-
dataloader.service.ts-
#Injectable()
export class DataloaderService {
constructor(private readonly categoryService: CategoryService) { }
createLoaders(): IDataloaders {
const subCategoryLoader = new DataLoader<ObjectId, Subcategory>(
async (keys: readonly ObjectId[]) =>
this.categoryService.findSubCategoryByBatch(keys as ObjectId[])
);
return {
subCategoryLoader
};
}
}
Then I category service(findSubCategoryByBatch)-
async findSubCategoryByBatch(Ids: ObjectId[]): Promise<(Subcategory | Error)[]> {
const categories = await this.subCategoryModel.find({ _id: { $in: Ids } });
const mappedResults = Ids.map(
(id) =>
categories.find((result) => result.id === id) ||
new Error(`Could not load owner ${id}`),
);
return mappedResults;
}
Then I call it -
#ResolveField('subCategory', () => [Subcategory])
getSubCategory(
#Parent() category: Category,
#Context() { loaders }: IGraphQLContext
) {
return loaders.subCategoryLoader.loadMany(category.subCategory)
}
Notice: I use loadMany function because subCategory is a array IDs.
But I am getting error. Here How to write function for loadMany function. Please help me. I need it. Please help me. please help me.
I am trying to dynamically translate some text to be displayed when a user clicks on the translate button, but I can't get it to save my values outside of the Promise. I haven't worked much with Promises and every example only shows console.log, rather than saving values outside of the Promise. I don't really understand how they work. Here is (most of) the code I am trying to fix:
constructor(props) {
super(props);
this.state = {
dynamicTranslate: this.props.dynamicTranslate,
};
}
// I've tried this method as both sync and async (with await) but neither work
googleTranslate = (key) => {
const translator = TranslatorFactory.createTranslator();
// translate returns a Promise
return translator.translate(key, i18n.locale)
.then((response) => {return response});
}
renderText() {
// getting some values....
// this loops through all the feedback information
for (var i = 0; i < components_feedback.length; i++) {
let label = (some string);
let value = (some string);
// to do: call google translate call here if Boolean(this.state.dynamicTranslate)
if (Boolean(this.state.dynamicTranslate)) {
// I am ultimately trying to save the translation string from googleTranslate()
// in label/value so I can push it into feedbacks
label = this.googleTranslate(label);
value = this.googleTranslate(value);
}
feedbacks.push({label: label, value: value, type: comp.type})
}
return (
// some stuff
feedbacks.map((feedback, index)) => {
// some stuff
<Text>{feedback.label}</Text>
<Text>{feedback.value}</Text>
// some other stuff
});
);
}
render() {
return (
<View>{this.renderText()}</View>
);
}
One of the issues I'm running into is that label/value is a Promise if translation is on. If I try to make renderText() an async method, it is also turned into a Promise which render() can't handle. No idea where to go from here.
Solved this issue. Solution is to put the loop in an async function that (ideally) gets called on construction. This loop was edited to await the returns and push to local arrays of labels and values then saves those in state. You can compare the length of those arrays to the expected length (compare length of last array being used to be positive that it has finished) and that is how you can know if the Promises have returned. Paraphrased code:
constructor(props) {
this.state = {
translatedLabels = []
translatedValues = []
}
this.asyncFunction()
}
asyncFunction = () => {
labels = []
for loop
label = await promise
labels.push(label)
//same for values
end for
this.setState({translatedLabels: labels})
}
//later
renderText() {
if (this.state.translatedLabels.length === whatever) {
// do your stuff as you know the async function has finished
}
}
render() {
return (
{this.renderText()}
);
}
I am trying to build my sub-component in function _buildComponent, and put result into render(), just have a look at my code below
the problem I met was the AsyncStorage.getItem() is running async, causing it render nothing there in render() method
...react
_buildComponent = async (key) => {
let val = await AsyncStorage.getItem(key)
console.log(key + ' : ' +val);
debugger;//code will run to here after ScrollableTabView finish rendering. but I need to build Arr first.
if(val == 1) return <PopularView tabLabel={key}>{key}</PopularView>
}
render() {
let Arr = Constants.TABS.map(item =
return this._buildComponent(item).done();
})
debugger;//code will run into here directly without waiting building Arr above, making Arr was null when rendering ScrollableTabView
return (
<ScrollableTabView
tabBarBackgroundColor='#2196F3'
tabBarInactiveTextColor='mintcream'
tabBarTextStyle={{marginTop:27}}
initialPage={0}
renderTabBar={() => <ScrollableTabBar/>}
>
{Arr}// Arr is null here because the _buildComponent method was not finish yet.
{/* <PopularView tabLabel='Java'>Java</PopularView>
<PopularView tabLabel='IOS'>IOS</PopularView>
<PopularView tabLabel='Android'>Android</PopularView>
<PopularView tabLabel='Javascript'>Javascript</PopularView> */}
</ScrollableTabView>
)
}
...
I have explain my issue in comment, please check it, thanks guys. I do not know what's the best practise to prepare variable before running render().
Try this solution which dynamically add tabs (Updated)
_buildComponent = async () => {
let tabsData = [];
await AsyncStorage.multiGet(Constants.TABS).then(response => {
Constants.TABS.forEach((item,index) =>
{
if(response[index][1] == 1) {
tabsData.push(response[index][0]); // key
}
}
);
// This only render once
this.setState({ tabLabels: tabsData })
})
}
componentDidMount() {
this._buildComponent()
}
render() {
const tabLabelList = this.state.tabLabels.map((key) => {
return (
<PopularView tabLabel={key}>{key}</PopularView>
)
})
return (
<ScrollableTabView
tabBarBackgroundColor='#2196F3'
tabBarInactiveTextColor='mintcream'
tabBarTextStyle={{marginTop:27}}
initialPage={0}
renderTabBar={() => <ScrollableTabBar/>}
>
{tabLabelList}
</ScrollableTabView>
)
}
I have a few elements in DOM and each of them has its own attribute 'id'. I need to create a function which iterates throw all of these elements and pushes values into the array. And the happy end of this story will be when this function will give me this array with all 'id' values.
I have tried this:
function getModelIds() {
let idList = [];
let modelId;
cy.get(someSelector).each(($el) => {
cy.wrap($el).invoke('attr', 'id').then(lid => {
modelId = lid;
idList.push(modelId);
});
});
return idList;
}
Will be very appreciated if you help me with rewriting this code into a function which will return an array with all 'id' values.
You can have a custom command:
Cypress.Commands.add(
'getAttributes',
{
prevSubject: true,
},
(subject, attr) => {
const attrList = [];
cy.wrap(subject).each($el => {
cy.wrap($el)
.invoke('attr', attr)
.then(lid => {
attrList.push(lid);
});
});
return cy.wrap(attrList);
}
);
You can use it later like this:
cy.get(someSelector)
.getAttributes('id')
.then(ids => {
cy.log(ids); // logs an array of strings that represent ids
});
I've been working to implement MobX into one of my classes, and I believe I'm close to have it working but I'd really appreciate if someone can point out where I'm going wrong here.
Essentially when the refreshJobs() function runs, I'd like the render() function to execute again. From my understanding, if I updated the observable object jobs, the computed functions (renderSubmittedJobs(), renderInProgressJobs()) would run again producing new values, then the render function would run again since those values have been updated.
However, what happens with this code is that it updates this.jobs (wrapped in an action), but neither of the computed functions execute - and I believe that is why render isn't ran again either.
Does anyone know what might be causing this issue? I really appreciate any direction with this.
#observer
export default class Jobs extends React.Component<ScreenProps<>> {
#observable jobs = {};
#computed get renderInProgressJobs() {
inProgressJobs = [];
for (key in this.jobs) {
if (jobs[key].status === "in progress") {
inProgressJobs.push(this.jobs[key]);
}
}
return this.renderJobComponents(inProgressJobs);
}
#computed get renderSubmittedJobs() {
submittedJobs = [];
for (key in this.jobs) {
console.log(key)
if (this.jobs[key].status !== "in progress") {
submittedJobs.push(this.jobs[key]);
}
}
return this.renderJobComponents(submittedJobs);
}
renderJobComponents(jobList: Array) {
return jobList.map((jobInfo, key) => {
return (
...
);
});
}
#observer
async refreshJobs() {
jobs = await grabClientJobs(refresh=true);
await runInAction("Updating Jobs", async () => {
this.jobs = jobs;
});
}
#observer
async componentWillMount() {
jobs = await grabClientJobs();
runInAction("Updating Jobs", async () => {
this.jobs = jobs;
});
}
#observer
render(): React.Node {
console.log('in jobs now');
return <BaseContainer title="Jobs" navigation={this.props.navigation} scrollable refresh={this.refreshJobs}>
<Tabs renderTabBar={()=> <ScrollableTab />} tabBarUnderlineStyle={style.secondaryBackground}>
<Tab heading="In Progress" textStyle={style.tabTextStyle} activeTextStyle={style.activeTabTextStyle}>
{ this.renderInProgressJobs }
<Button full style={[style.secondaryBackground, style.newJob]}>
<Text>CREATE NEW JOB</Text>
</Button>
</Tab>
<Tab heading="Submitted" textStyle={style.tabTextStyle} activeTextStyle={style.activeTabTextStyle}>
{ this.renderSubmittedJobs }
</Tab>
</Tabs>
</BaseContainer>;
}
}
few mistakes here:
you can't re-assign another value to the observable variable, it'll destroy the observable. You need to mutate the observable. For example, you can directly assign values to existing properties or use extendObservable for assigning new properties to observable object.
If you use MobX < 4, adding new properties the observable object will not trigger changes because the properties are set when the observable object was created. extendObservable may work but it's also limited. Use observable Map instead.
#observer should be used for component class (or SFC), not member functions inside of the class