I have an application that queries the stock exchange in real time, but when I open the application the first time it does not update any displayed value, as if it were hardcoded, but when I save the file (ctrl + S) it starts to update normally , Can anyone help me with this?
description code below:
this function is listening the data on firebase;
ticketRT is my state that is not updating at first time
Object.keys(subscriptionStocks).forEach((stock) => {
if(!subscriptionStocks[stock].listener) {
firebase.database().ref(`${endPointStocks}/${stock}`).on('value', async data => {
let stock = data.val();
if (stock) {
stockArray[stock.ticket] = stock;
setTicketRT(stockArray);
await updateListStocks(stock);
} else {
console.log(`[listenerStock]: Não foi possível cadastrar o ativo "${stock}"`);
}
});
subscriptionStocks[stock].listener = true;
this function updates the stock list
let tmpStock = {};
console.log('LENGTH 11111', stockArray.length);
if (stockArray.length === 0) {
console.log('LENGTH 22222 ≥≥≥ 2', stockArray.length);
tmpStock[stock.ticket] = stock;
stockArray.push(tmpStock);
setTicketRT(stockArray);
updateWalletBalance();
} else {
const foundStockInArray = stockArray.some(
el => {
let inStock = el[Object.keys(el)[0]];
return inStock.ticket == stock.ticket;
}
);
if (foundStockInArray) {
updateStock(stock);
} else {
tmpStock[stock.ticket] = stock;
stockArray.push(tmpStock);
setTicketRT(stockArray);
updateWalletBalance();
}
}
this is my FlatList that is not updating
<FlatList
style={styles.actionList}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
data={ticketRT}
extraData={(item, index) => {
if(ticketRT !== undefined) {
let stocks = ticketRT[index];
let stock = stocks[Object.keys(stocks)[0]];
return stock.ticket;
}
}}
keyExtractor={(item, index ) => {
if(ticketRT !== undefined) {
let stocks = ticketRT[index];
let stock = stocks[Object.keys(stocks)[0]];
return stock.ticket;
}
}}
renderItem={({ index }) => {
let stocks = ticketRT[index];
let stock = stocks[Object.keys(stocks)[0]];
return <Ativos data={stock} />
}}
contentInset={{ bottom: 10, top: -5 }}
/>
ALL CODE IS FOUNDED HERE: https://gist.github.com/paulorod07/4e74976345a6a68b0e32755cf5ae1c46
Related
what exactly is happening is when i select the delivery service onChangeService i'm setting the next dropdown i.e. carrier's list.Also i'm setting the selected carrier as per the service.But all the time value is getting set correctly in {this.state.selectedCarrierName} but still i can show its label only.lists contain label an value pair
async onChangeService(value) {
//{ ...this.props.deliveryOptionsValue, selected: value.value === value }
this.setState({ newCarrierList: [], selectedCarrierName: '', selectedCararierName: '' });
const priceDeliveryService = this.props.orderDetailsDTO.priceDeliveryServiceDTOs;
console.log("carriers", JSON.stringify(this.props.carriers));
var newList = [];
var carrier = '';
await priceDeliveryService.forEach(m => {
console.log("compare", m.serviceId === value.id);
if (m.serviceId === value.id) {
console.log("carrier", JSON.stringify(this.props.carriers));
let l = this.props.orderDetailsDTO.carriers.filter(n => n.id === m.carrierId);
console.log("l", l);
if (l !== undefined) {
// / orderList: [...this.state.orderList, ...content]
// this.setState({ newCarrierList: [...this.state.newCarrierList, ...l[0]] });
newList.push(l[0]);
console.log("defa", newList);
if (m.defaultCarrierService) {
this.setState({ selectedCarrier: l[0], selectedCarrierName: l[0].name });
carrier = l[0].name;
} else {
this.setState({ selectedCarrier: newList[0], selectedCarrierName: newList[0].name });
carrier = newList[0].name;
}
}
}
});
const list = newList.map(item => ({
label: item.name,
value: item
}));
this.setState({ newCarrierListValue: list, newCarrierList: newList })
console.log("newCarrierListValue", list);
console.log("newCarrierList", newList);
// console.log("carrier service", p.carrierName, value.id);
const carrierServices = this.props.orderDetailsDTO.carrierServiceDTO;
console.log(carrierServices.length);
const pi = await this.setCarrierService(carrierServices, value, carrier);
// let pi;
// for (let i = 0; i < carrierServices.length; i++) {
// console.log("if", carrierServices[i].cdlServiceId == value.id, carrierServices[i].carrierName === carrier)
// if (carrierServices[i].cdlServiceId == value.id && carrierServices[i].carrierName === carrier) {
// console.log("mathced data", carrierServices[i]);
// pi = carrierServices[i];
// console.log(pi);
// break;
// }
// }
this.setState({ carrierService: pi.serviceName, carrierServices: carrierServices });
console.log(pi.serviceName);
}
<Dropdown required
label="Select delivery option"
data={this.props.deliveryOptionsValue}
// enableSearch
defaultValue={1}
value={this.state.selectedDeliveryOptionName}
onChange={(value) => {
console.log(" change value", value);
this.setState({ selectedDeliveryOptionName: value.name, selectedDeliveryOption: value, deliveryOptionError: false, });
this.onChangeService(value);
}} />
<Dropdown
required
label="Select a carrier"
data={this.state.newCarrierListValue}
// selectedValue={this.state.selectedCarrierName}
value={this.state.selectedCarrierName}
onChange={value => {
// console.log("value", value);
this.setState({ selectedCarrierName: value.name, selectedCarrier: value });
this.onChangeCarrier(value, this.state.selectedDeliveryOption);
}} />
I'm using default example of NormalPeoplePicker from https://developer.microsoft.com/en-us/fluentui#/controls/web/peoplepicker#IPeoplePickerProps.
When the dropdown displays it cuts off longer items (example: 'Anny Lundqvist, Junior Manager of Soft..'). How do I make it wider, so that the full item's text displays?
import * as React from 'react';
import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
import { IPersonaProps } from 'office-ui-fabric-react/lib/Persona';
import { IBasePickerSuggestionsProps, NormalPeoplePicker, ValidationState } from 'office-ui-fabric-react/lib/Pickers';
import { people, mru } from '#uifabric/example-data';
const suggestionProps: IBasePickerSuggestionsProps = {
suggestionsHeaderText: 'Suggested People',
mostRecentlyUsedHeaderText: 'Suggested Contacts',
noResultsFoundText: 'No results found',
loadingText: 'Loading',
showRemoveButtons: true,
suggestionsAvailableAlertText: 'People Picker Suggestions available',
suggestionsContainerAriaLabel: 'Suggested contacts',
};
const checkboxStyles = {
root: {
marginTop: 10,
},
};
export const PeoplePickerNormalExample: React.FunctionComponent = () => {
const [delayResults, setDelayResults] = React.useState(false);
const [isPickerDisabled, setIsPickerDisabled] = React.useState(false);
const [mostRecentlyUsed, setMostRecentlyUsed] = React.useState<IPersonaProps[]>(mru);
const [peopleList, setPeopleList] = React.useState<IPersonaProps[]>(people);
const picker = React.useRef(null);
const onFilterChanged = (
filterText: string,
currentPersonas: IPersonaProps[],
limitResults?: number,
): IPersonaProps[] | Promise<IPersonaProps[]> => {
if (filterText) {
let filteredPersonas: IPersonaProps[] = filterPersonasByText(filterText);
filteredPersonas = removeDuplicates(filteredPersonas, currentPersonas);
filteredPersonas = limitResults ? filteredPersonas.slice(0, limitResults) : filteredPersonas;
return filterPromise(filteredPersonas);
} else {
return [];
}
};
const filterPersonasByText = (filterText: string): IPersonaProps[] => {
return peopleList.filter(item => doesTextStartWith(item.text as string, filterText));
};
const filterPromise = (personasToReturn: IPersonaProps[]): IPersonaProps[] | Promise<IPersonaProps[]> => {
if (delayResults) {
return convertResultsToPromise(personasToReturn);
} else {
return personasToReturn;
}
};
const returnMostRecentlyUsed = (currentPersonas: IPersonaProps[]): IPersonaProps[] | Promise<IPersonaProps[]> => {
return filterPromise(removeDuplicates(mostRecentlyUsed, currentPersonas));
};
const onRemoveSuggestion = (item: IPersonaProps): void => {
const indexPeopleList: number = peopleList.indexOf(item);
const indexMostRecentlyUsed: number = mostRecentlyUsed.indexOf(item);
if (indexPeopleList >= 0) {
const newPeople: IPersonaProps[] = peopleList
.slice(0, indexPeopleList)
.concat(peopleList.slice(indexPeopleList + 1));
setPeopleList(newPeople);
}
if (indexMostRecentlyUsed >= 0) {
const newSuggestedPeople: IPersonaProps[] = mostRecentlyUsed
.slice(0, indexMostRecentlyUsed)
.concat(mostRecentlyUsed.slice(indexMostRecentlyUsed + 1));
setMostRecentlyUsed(newSuggestedPeople);
}
};
const onDisabledButtonClick = (): void => {
setIsPickerDisabled(!isPickerDisabled);
};
const onToggleDelayResultsChange = (): void => {
setDelayResults(!delayResults);
};
return (
<div>
<NormalPeoplePicker
// eslint-disable-next-line react/jsx-no-bind
onResolveSuggestions={onFilterChanged}
// eslint-disable-next-line react/jsx-no-bind
onEmptyInputFocus={returnMostRecentlyUsed}
getTextFromItem={getTextFromItem}
pickerSuggestionsProps={suggestionProps}
className={'ms-PeoplePicker'}
key={'normal'}
// eslint-disable-next-line react/jsx-no-bind
onRemoveSuggestion={onRemoveSuggestion}
onValidateInput={validateInput}
removeButtonAriaLabel={'Remove'}
inputProps={{
onBlur: (ev: React.FocusEvent<HTMLInputElement>) => console.log('onBlur called'),
onFocus: (ev: React.FocusEvent<HTMLInputElement>) => console.log('onFocus called'),
'aria-label': 'People Picker',
}}
componentRef={picker}
onInputChange={onInputChange}
resolveDelay={300}
disabled={isPickerDisabled}
/>
<Checkbox
label="Disable People Picker"
checked={isPickerDisabled}
// eslint-disable-next-line react/jsx-no-bind
onChange={onDisabledButtonClick}
styles={checkboxStyles}
/>
<Checkbox
label="Delay Suggestion Results"
defaultChecked={delayResults}
// eslint-disable-next-line react/jsx-no-bind
onChange={onToggleDelayResultsChange}
styles={checkboxStyles}
/>
</div>
);
};
function doesTextStartWith(text: string, filterText: string): boolean {
return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0;
}
function removeDuplicates(personas: IPersonaProps[], possibleDupes: IPersonaProps[]) {
return personas.filter(persona => !listContainsPersona(persona, possibleDupes));
}
function listContainsPersona(persona: IPersonaProps, personas: IPersonaProps[]) {
if (!personas || !personas.length || personas.length === 0) {
return false;
}
return personas.filter(item => item.text === persona.text).length > 0;
}
function convertResultsToPromise(results: IPersonaProps[]): Promise<IPersonaProps[]> {
return new Promise<IPersonaProps[]>((resolve, reject) => setTimeout(() => resolve(results), 2000));
}
function getTextFromItem(persona: IPersonaProps): string {
return persona.text as string;
}
function validateInput(input: string): ValidationState {
if (input.indexOf('#') !== -1) {
return ValidationState.valid;
} else if (input.length > 1) {
return ValidationState.warning;
} else {
return ValidationState.invalid;
}
}
/**
* Takes in the picker input and modifies it in whichever way
* the caller wants, i.e. parsing entries copied from Outlook (sample
* input: "Aaron Reid <aaron>").
*
* #param input The text entered into the picker.
*/
function onInputChange(input: string): string {
const outlookRegEx = /<.*>/g;
const emailAddress = outlookRegEx.exec(input);
if (emailAddress && emailAddress[0]) {
return emailAddress[0].substring(1, emailAddress[0].length - 1);
}
return input;
}
Component which renders suggestion list have fixed width of 180px. Take a look at PeoplePickerItemSuggestion.styles.ts.
What you can do is to modify this class .ms-PeoplePicker-Persona:
.ms-PeoplePicker-Persona {
width: 260px; // Or what ever you want
}
UPDATE - Solution from comments
Change width trough styles property of PeoplePickerItemSuggestion Component
const onRenderSuggestionsItem = (personaProps, suggestionsProps) => (
<PeoplePickerItemSuggestion
personaProps={personaProps}
suggestionsProps={suggestionsProps}
styles={{ personaWrapper: { width: '100%' }}}
/>
);
<NormalPeoplePicker
onRenderSuggestionsItem={onRenderSuggestionsItem}
pickerCalloutProps={{ calloutWidth: 500 }}
...restProps
/>
Working Codepen example
For more information how to customize components read Component Styling.
I'm loading a dynamic form in a FlatList. I'm supposed to add few rows with UI elements such as TextInput, checkbox, etc. based on a condition. For example, I have a dropdown, when I select a value, I have to add a row with a button and remove that row when I select another value.
My issue is that whenever I select a value in the dropdown to add a row with button, FlatList is adding duplicate rows and they are not visible as objects in my array when I debug them. I'm using Redux to manage my application state and updating my array in reducers.
I have to display objects in my array in FlatList without any duplicates using Redux for state management.
Code:
<FlatList
key={Math.floor(Math.random())}
ref={(ref) => { this.flatListRef = ref; }}
data={this.state.mainArray}
renderItem={this._renderItem}
keyExtractor={({ item, id }) => String(id)}
extraData={this.prop}
keyboardDismissMode="on-drag"
showsVerticalScrollIndicator={false}
scrollEnabled={true}
removeClippedSubviews={false}
scrollsToTop={false}
initialNumToRender={100}
/>
componentWillReceiveProps(nextProps) {
this.setState({mainArray: nextProps.mainArray});
}
Updating array in Reducer:
case VALIDATE_DEPENDENCY: {
// adding or removing dependency questions
let dependingQues = [];
let formArrayTemp = [...state.mainArray];
let exists;
// console.log("formArrayTemp123", formArrayTemp);
if (action.item.isDependentQuestion) {
if (action.item.dependentQuestionsArray.length > 0) {
let dependent_ques = action.item.dependentQuestionsArray[0];
state.depending_questions_array.filter((obj, id) => {
if (JSON.stringify(obj.key_array) === JSON.stringify(dependent_ques.key)) {
dependingQues.push(obj);
}
});
// console.log("dependingQues123", dependingQues);
if (dependent_ques.answer === action.item.answer) {
dependingQues.map((obj, id) => {
exists = formArrayTemp.filter((res, idx) => {
if (JSON.stringify(res.key_array) === JSON.stringify(obj.key_array)) {
return res;
}
});
// console.log("exists123", exists);
if (exists.length === 0) {
formArrayTemp.splice(action.index + id + 1, 0, obj);
// console.log("mjkgthbythyhy", action.index + id + 1);
}
});
}
else {
let objIndex = formArrayTemp.findIndex(obj => JSON.stringify(obj.key_array) === JSON.stringify(dependent_ques.key));
if (objIndex !== -1) {
formArrayTemp[objIndex].answer = "";
formArrayTemp[objIndex].borderColor = "black";
formArrayTemp.splice(objIndex, 1);
// console.log("frtg6hyjukiu", formArrayTemp);
}
}
}
}
// adding or removing dependent sections
let dependentSections = [];
let tempArr = [];
let count = 0;
if (action.item.isDependent) {
if (action.item.dependentArray.length > 0) {
let dependent_section = action.item.dependentArray[0];
state.dependent_sections_array.filter((obj, id) => {
if (obj.section_id === dependent_section.section_id) {
dependentSections.push(obj);
}
});
// console.log("dependentSections123", dependentSections);
let lastIndex;
formArrayTemp.filter((res, id) => {
if (action.item.section_id === res.section_id && res.dependentArray &&
JSON.stringify(action.item.dependentArray) === JSON.stringify(res.dependentArray)) {
tempArr.push(res);
lastIndex = formArrayTemp.FindLastIndex(a => a.section_id === res.section_id);
}
});
// console.log("lastIndex123", lastIndex);
tempArr.map((obj, id) => {
if (obj.answer === obj.dependentArray[0].answer) {
count++;
}
});
if (dependent_section.answer === action.item.answer) {
dependentSections.map((obj, id) => {
if (formArrayTemp.contains(obj) === false) {
formArrayTemp.splice(lastIndex + id + 1, 0, obj);
// console.log("cfrererfre", formArrayTemp);
}
});
}
else {
let countTemp = [];
if (count === 0) {
let countTemp = [];
dependentSections.filter((res, id) => {
if (formArrayTemp.contains(res) === true) {
formArrayTemp.filter((obj, idx) => {
if (obj.section_id === res.section_id) {
obj.answer = "";
obj.borderColor = "black";
countTemp.push(obj);
}
});
}
});
let jobsUnique = Array.from(new Set(countTemp));
formArrayTemp = formArrayTemp.filter(item => !jobsUnique.includes(item));
// console.log("frefrefre123", formArrayTemp);
// return { ...state, mainArray: [...formArrayTemp] }
}
}
}
}
console.log("formArray123", formArrayTemp);
formArrayTemp.sort((a, b) => {
return a.posiiton - b.position;
});
return { ...state, mainArray: formArrayTemp }
};
Update
After researching this issue I came across this issue #24206 in GitHub. There it states:
There's a few things you aren't doing quite correctly here. Each time the render function runs you are creating a new array object for your data, so React has to rerender the entire list each time, you're renderItem function and keyExtractor function are also remade each rerender, and so the FlatList has to be rerun. You're also using the index for your key which means as soon as anything moves it will rerender everything after that point. I would recommend looking at what does/doesn't change when you rerun things (arrays, functions, object), and why the keyExtractor is important for reducing re-renders.
So I tried commenting KeyExtractor prop of FlatList and the issue got resolved. But this is causing issue in another form. How can I resolve that?
I am trying to enable date range using react-native-calendars. On my app, the calendar loads a few 'markedDates'; now I need to implement a start and end date functionality without affecting these initial dates. Unfortunately, I am struggling to achieve that. Any ideas on how can I do that?
Thank you in advance.
Pseudo-code
Load calendar with marked dates
Tap on start date
Tap on end date
Continue
Component
export default class Dates extends Component {
static navigationOptions = {
title: 'Choose dates',
}
constructor(props) {
super(props)
this.state = {
selected: undefined,
marked: undefined,
}
}
componentDidMount() {
this._markDate()
}
_markDate = () => {
nextDay = []
const marked = {
[nextDay]: { selected: true, marked: true },
}
Util._findShows(resp => {
resp.map(data => {
nextDay.push(data.date)
})
var obj = nextDay.reduce((c, v) => Object.assign(c, { [v]: { marked: true, dotColor: 'black' } }), {})
this.setState({ marked: obj })
})
}
_selectDate = obj => {
this.setState({ selected: obj.dateString })
}
render() {
return (
<View style={styles.container}>
<CalendarList
// Callback which gets executed when visible months change in scroll view. Default = undefined
onVisibleMonthsChange={months => {
console.log('now these months are visible', months)
}}
// Max amount of months allowed to scroll to the past. Default = 50
pastScrollRange={0}
// Max amount of months allowed to scroll to the future. Default = 50
futureScrollRange={12}
// Enable or disable scrolling of calendar list
scrollEnabled={true}
// Enable or disable vertical scroll indicator. Default = false
showScrollIndicator={true}
markedDates={
// [this.state.selected]: { selected: true, disableTouchEvent: true, selectedDotColor: 'orange' },
this.state.marked
}
onDayPress={day => {
this._selectDate(day)
}}
/>
<View style={styles.ctaArea}>
<TouchableOpacity style={styles.button} onPress={() => this.props.navigation.navigate('Dates')}>
<Text style={styles.btTitle}>Continue</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
I had the same struggle but so I decided to make my own version.
I'm sure it can be done better and have more functionalities but it works okay for me
const [dates, setDates] = useState({});
// get array of all the dates between start and end dates
var getDaysArray = function(start, end) {
for (var arr=[], dt = new Date(start); dt <= new Date(end); dt.setDate(dt.getDate() + 1)){
arr.push(useFormatDate(new Date(dt)));
}
return arr;
};
// empty object
const emptyObj = (obj: Object) => {
var props = Object.getOwnPropertyNames(obj);
for (var i = 0; i < props.length; i++) {
delete dates[props[i]];
}
}
// check if first date is smaller or equals to second date
const compareDate = function(first: string, second: string) {
return (new Date(first) <= new Date(second) ? true : false);
}
// fill with color the date between first and second date selected
const fillRangeDate = function(first: string, second: string) {
emptyObj(dates);
let newDates = dates;
newDates[first]={selected: true, Colors[colorScheme].tint};
newDates[second]={selected: true, color: Colors[colorScheme].tint};
var range = getDaysArray(first, second);
for (var i = 1; i < range.length - 1; i++)
newDates[range[i]]={color: '#70d7c7', textColor: 'white'};
setDates({...newDates})
}
const selectDate = (day) => {
let selectedDate = day.dateString;
let newDates = dates;
// if 2 dates are selected
if (Object.keys(dates).length >= 2) {
var props = Object.getOwnPropertyNames(dates);
if (compareDate(props[0], selectedDate)) {
fillRangeDate(props[0], selectedDate);
} else {
emptyObj(dates);
}
} else {
// 1 date selected
if (Object.keys(dates).length == 0) {
newDates[selectedDate]={selected: true, color: Colors[colorScheme].tint};
} else if (Object.keys(dates).length == 1) { // 2 dates selected
newDates[selectedDate]={selected: true, color: Colors[colorScheme].tint};
// if 2nd date < 1st date, cancel range
var props = Object.getOwnPropertyNames(dates);
if (compareDate(props[0], props[1])) {
var range = getDaysArray(props[0], props[1]);
for (var i = 1; i < range.length - 1; i++) {
newDates[range[i]]={color: '#70d7c7', textColor: 'white'};
}
} else {
emptyObj(dates);
}
}
}
setDates({...newDates})
}
You'll also need to add this function that I implemented as a hook:
const useFormatDate = (date: Date) => {
function padTo2Digits(num) {
return num.toString().padStart(2, '0');
}
return [
date.getFullYear(),
padTo2Digits(date.getMonth() + 1),
padTo2Digits(date.getDate()),
].join('-');
};
Help me to improve this code and maybe create a merge request on the wix/react-native-calendar
Hope this helps
I have to show options menu using conditional check on data coming from the server. Here is my code:
function renderMoreOptionsOnNavbar(groupInfo){
console.log('hey check this out', groupInfo)
if (groupInfo.user_joined) {
var formData = new FormData();
formData.append('user_id', global.currentUser.USER_ID);
formData.append('slug', groupInfo.id);
var adminsIdsArray = []
ajaxPost({
url: 'community',
basePath: 'lumen',
params: formData
}).then(res => {
if(!res.err_code) {
console.log('This is what you need', res)
const communityAdminsArray = res.community_admins
adminsIdsArray = communityAdminsArray.map(function(user) {
return user.user_id
})
console.log('AdminsArray', adminsIdsArray.includes(global.currentUser.USER_ID))
}
})
const menuOptions = adminsIdsArray.includes(global.currentUser.USER_ID) ? ['Switch off notifications', 'Edit group information', 'Quit group'] : ['Switch off notifications', 'Quit group']
const menuHeight = menuOptions.length*40
console.log('options', menuOptions)
return(
<ModalDropdown options={menuOptions} style={styles.dropDownView} dropdownStyle = {styles.dropdownStyle, {height: menuHeight, width: 175}} adjustFrame = {adjustDropDownFrame}
renderSeparator = {renderDropDownSeparator} dropdownTextStyle = {styles.dropDownOptionText}
onSelect = {onSelectingDropDownOption.bind(this, groupInfo)}
showsVerticalScrollIndicator = {false}
>
<View style={styles.dropDownButtonView}>
<Image
source={require('../../Assets/vertical_dots_menu.png')}
resizeMode = {Image.resizeMode.center}
style = {styles.dropDownBaseButton}
/>
</View>
</ModalDropdown>
)
}
else {
return null
}
}
The options in menu loading before data. Can some one tell me, how to pause rendering until data loads.
You should follow this pattern to achieve what you want:
state = {requiredData: null}
fetchDataFunction().then((resp)=>{
...
this.setState({requiredData: resp}) // I assume the response of fetch is what you need
})
render() {
if (this.state.requiredData === null) {
return null // you can use a spinner instead null
} else {
return (
... // your main view
)
}
}