Close accordions on radio button click - javascript

I have an accordion component in my React Native app which is from galio framework . I have populated it with api data. The accordion closes if you click in the title but I want it to close when I select a radio button. Here is my code:
const Step3 = () => {
const [questions, setQuestions] = useState([]);
const [answers, setAnswers] = useState([]);
const [icon, setIcons] = useState([]);
const [iconColor, setIconsColor] = useState([])
const [refreshing, setRefreshing] = useState(true);
const getQuestions = async () => {
const locale = i18next.language; // TODO: get current locale
const response = await apiStandarts.get(`/questions?locale=${locale}`, {
params: { active: 1, _sortId: [1,2] , _sort: "sortId:ASC"},
});
setRefreshing(false)
setQuestions(response.data);
};
const isOptionSelected = (option) => {
const answer = answers[option.question];
if (answer) {
return option.id == answer.id;
}
return false;
};
const questionIcon = async () => {
const response = await apiStandarts.get(`/commitments-icons`);
setIcons(response.data)
}
const questionIconColor = async () => {
const response = await apiStandarts.get(`/commitments`);
setIconsColor(response.data)
}
const objectMap = (obj, fn) =>
Object.fromEntries(
Object.entries(obj).map(([k, v], i) => [k, fn(v, k, i)])
);
const newAnswers = objectMap(answers, (item) => {
return [item.id, item.description];
});
// useEffect(() => {
// questionIcon();
// }, []);
useEffect(() => {
questionIcon();
getQuestions();
}, []);
const OptionList = (groupOption) => {
return (
groupOption.options.map((item, index) => {
const clickedRadio = () => {
const selectedOption = { [item.question]: { ...item } };
setAnswers({ ...answers, ...selectedOption });
};
let status = isOptionSelected(item) ? true : false;
return (
<Radio
initialValue={status}
label={item.description}
onChange={() => clickedRadio()}
color="rgba(0,0,0,.54)"
radioInnerStyle={{backgroundColor: "#3671a6"}}
labelStyle={ styles.label}
containerStyle={{ width: 300, padding: 5 }}
/>
);
})
);
};
return (
<View style={styles.container}>
<Text style={{ fontWeight: "bold", fontSize: 12, color: "#6B24" }}>
{t("Choose an option/Scroll for more questions")}
</Text>
<FlatList
data={questions}
keyExtractor={(result) => result.id.toString()}
contentContainerStyle={{ padding: 5, paddingBottom: 5 }}
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={getQuestions} />}
renderItem={({ item, index }) => {
const arr = [item.commitments[0].commitment_icon];
const questIcon = arr.filter(i => Boolean(i)).map(id => icon.find(o => o.id === id)?.image?.url);
const imgUrl = APIURL + questIcon;
function iconBgColor(){
let bgColor
switch (item.commitments[0].commitment_icon) {
case 1:
bgColor="#78bad3"
break;
case 3:
bgColor = "#027a95"
break;
case 6:
bgColor = "#027a95"
break;
case 4:
bgColor = '#1fc191'
break;
case 5:
bgColor = '#78bad3'
break;
case 2:
bgColor = "#e4da4d"
break;
case 7:
bgColor = "#1fc191"
break;
default:
bgColor= "#fff"
break;
}
return bgColor;
}
const backgroundColor = iconBgColor(item.commitments[0].commitment_icon)
const data = [
{
title: (<>
<View style={[styles.iconWrapper,{backgroundColor: backgroundColor}]}>
{
imgUrl.indexOf('.svg') > 0 ? <SvgUri uri={APIURL + questIcon} height={20} width={20} style={styles.iconColor}/> : null
}
</View>
<Text style={styles.text}>{item.sortId}.</Text>
<Text style={styles.text} key={item.description}>{item.description}</Text>
</>),
content:<View><OptionList key={item?.question_options.id} options={item?.question_options}></OptionList></View>
},
];
return (
<View style={styles.groupOptions} key={index}>
<Accordion style={styles.accordion} headerStyle={styles.headerStyle} contentStyle={styles.contentStyle} dataArray={data} opened={index} />
</View>
);
}}
/>
</View>
);
};
Any ideas how to achieve what I want? Any answer would be appreciated, thanks.

you have a next code:
<Accordion
style={styles.accordion}
headerStyle={styles.headerStyle}
contentStyle={styles.contentStyle}
dataArray={data}
opened={index} // here you should have "isAccordionOpen"
/>
and handle a variable in state your Step3 component.
In this function you should to change this variable "isAccordionOpen"
const clickedRadio = () => {
const selectedOption = { [item.question]: { ...item } };
setAnswers({ ...answers, ...selectedOption });
}

As I have checked in the docs and Galio Library there seems no prop to manage Accordion after the first render cycle.
We can only manage the Accordion initially on the first render.
If you have to manage it then you have to make changes in the Galio library code.
Here I am attaching the Sample code base, Hoping that it might help you.
Sample Code:
import React, { useState } from 'react'
import { View } from 'react-native'
import { Accordion, Block, Checkbox } from 'galio-framework';
const App = () => {
const [openIndex, setOpenIndex] = useState(-1)
const radioClickHandler = (id, status) => {
setOpenIndex(-1)
}
const data = [
{
title: "First Chapter",
content: (
<Checkbox
onChange={radioClickHandler.bind(null, 'first')}
color="primary"
label="Primary Checkbox"
/>
)
},
{
title: "Second Chapter",
content: (
<Checkbox
onChange={radioClickHandler.bind(null, 'second')}
color="primary"
label="Secondary Checkbox"
/>
)
}
]
const onOpen = (prop) => {
setOpenIndex(prop?.title === "First Chapter" ? 0 : 1)
}
return (
<View style={{ flex: 1, justifyContent: 'center' }}>
<Block style={{ height: 200 }}>
<Accordion
dataArray={data}
opened={openIndex}
onAccordionOpen={onOpen}
/>
</Block>
</View>
)
}
export default App
Here are the changes in the library code to manage the collapse Accordion Component.
file Path: 'node_modules/galio-framework-src-Accordion.js'
Add Below Code
const [selected, setSelected] = useState(opened);
useEffect(() => {
setSelected(opened)
}, [opened])

Related

Search Funtion in An Array React.js

I have an array of universities
And I need to make a search funtion.
My search implementation works perfectly and finds the university that I type.
However when I select the option, it confuses itself and always select by new index.
For example my array is ["A.T. Still University", "Abilene Christian University", "Abraham Baldwin University", "Academy for Five Element University" ... ]
In here, A.T. Still University is at the 0 index originally. and when I make a search with filter, it creates a new array. I type "Abilene" for example and it brings me a new array with results and "Abilene" becomes at the 0 index. However it doesnt select this one and keeps selecting "A.T. Still University" which has the original 0 index.
Can someone help me how to fix this problem ?
I want to be able to select what I type in search area.
My code is below
const SignupStep5 = forwardRef((props, ref) => {
const dispatch = useDispatch();
const userInfo = useSelector(state => state.profile.user);
const universityList = useSelector(state => state.config.universities);
const isFetchingUniversity = useSelector(state =>
isLoadingSelector([fetchUniversities], state),
);
//State
const [
selectedUniversityId,
setSelectedUniversityId,
selectedUniversityIdRef,
] = useStateRef(null);
const [choosenUniversity, setChoosenUniversity, choosenUniversityRef] =
useStateRef('');
const [choosenUniversityId, setChoosenUniversityId, choosenUniversityIdRef] =
useStateRef('');
useEffect(() => {
if (universityList.length) {
if (props.activeIndex == 5 && userInfo && userInfo.university) {
const index = universityList.findIndex(university =>
isEqual(university, userInfo.university),
);
if (index !== -1) {
setSelectedUniversityId(index);
setChoosenUniversity(userInfo.university);
}
}
}
}, [universityList]);
const renderHeader = () => (
<View>
<View style={styles.modalHeaderContainer}>
<Text style={styles.modalHeaderText}>
{strings.aboutMe.selectUniversity}
</Text>
<Touchable
style={styles.modalHeaderTextContainer}
onPress={() => {
if (selectedUniversityIdRef.current != null) {
setChoosenUniversityId(selectedUniversityIdRef.current);
setChoosenUniversity(
universityList[selectedUniversityIdRef.current],
);
closeBottomSheet();
}
}}>
<Text style={styles.modalHeaderSelectText}>
{strings.common.select}
</Text>
</Touchable>
</View>
<View style={styles.modalHeaderLine}></View>
</View>
);
const renderItem = ({item, index}) => (
<Touchable
style={
selectedUniversityIdRef.current === index
? styles.modalChildContainerSelected
: styles.modalChildContainer
}
onPress={() => handleSelection(index)}>
<Text style={styles.modalChildText}>{item}</Text>
</Touchable>
);
const handleSelection = id => {
const selectedId = selectedUniversityIdRef.current;
if (selectedId === id) setSelectedUniversityId(null);
else setSelectedUniversityId(id);
};
const onOverlayPress = () => {
if (choosenUniversityRef.current) {
const index = universityList.findIndex(
university => university === choosenUniversityRef.current,
);
if (index !== -1) {
setSelectedUniversityId(index);
}
} else if (
selectedUniversityIdRef.current != null &&
!choosenUniversityRef.current
) {
setSelectedUniversityId(null);
}
setModalVisible(false);
};
const [searchField, setSearchField] = useState('');
const searchInputFields = () => {
const filteredUniversity = universityList.filter(value => {
return value.toLowerCase().includes(searchField.toLowerCase());
});
return filteredUniversity;
};
return (
<>
<Portal>
{props.activeIndex == 5 && (
<BottomSheet
ref={bottomSheetRef}
snapPoints={snapPoints}
handleComponent={renderHeader}
backdropComponent={renderBackdrop}
onAnimate={handleSheetChanges}>
<TextInput
onChangeText={value => setSearchField(value)}
value={searchField}
style={{padding: 10, alignSelf: 'center'}}
placeholder="Search"
placeholderTextColor={'gray'}
/>
<BottomSheetFlatList
data={searchField ? searchInputFields() : universityList}
keyExtractor={(item, index) => index.toString()}
renderItem={renderItem}
contentContainerStyle={styles.modalChildStyle}
extraData={selectedUniversityIdRef.current}
/>
</BottomSheet>
)}
</Portal>
</>
);
});
export default SignupStep5;

UseState not update when using alongside with redux dispatch in arrow function

I'm making an app that have notes, and when develop the delete function, i faced this error, the useState do not update when use alongside with redux dispatch function ( even the redux function run, the useState do not run ) , i tried to create the same issue on codesandbox, but weird is it WORKING TOTALLY FINE ON WEB?!
Here is the code:
NoteList.tsx
function NoteList(props: noteListI) {
const { title, note, id, date, selectStatus } = props; //they are props
const nav = useNavigation(); //for navigation
const [isDeleteChecked, setDeleteChecked] = useState(false);
const dispatch = useDispatch();
const data = useSelector((state: RootState) => state.persistedReducer.note); // note item from redux
const toggleSelectedButton = useSelector(
(state: RootState) => state.toggle.enableSelectedButton
); // to show selected button icon
const onNavDetail = () => {
nav.navigate(RouteName.EDIT_NOTE, {
date: date,
note: note,
header: title,
id: id,
});
};
const toggleSelectButton = () => {
dispatch(switchToggle());
}; // toggle delete button function
const setDeleteItem = () => {
setDeleteChecked(!isDeleteChecked);
dispatch(toggleSelect({ id: id }));
}; ////==>>> the issue here the 'setDeleteChecked' not even work
return (
<TouchableOpacity
onLongPress={() => {
toggleSelectButton();
}}
style={CONTAINER}
onPress={() => (!toggleSelectedButton ? onNavDetail() : setDeleteItem())}
>
<View style={NOTE_ITEM_CONTAINER}>
<Text>{isDeleteChecked?.toString()}</Text> ==>always false, why????!
<View>
<View row centerV style={HEADER_CONTAINER}>
<View>
<AppText bold style={HEADER_TEXT}>
{title}
</AppText>
</View>
{toggleSelectedButton && (
<View>
{selectStatus ? ( ===> this is from redux and work but slow
<CheckIcon name="checkcircle" size={size.iconSize} />
) : (
<CheckIcon name="checkcircleo" size={size.iconSize} />
)}
</View>
)}
</View>
<View style={NOTE_CONTAINER}>
<AppText numberOfLines={7}>{note}</AppText>
</View>
</View>
<View
style={{
alignSelf: "flex-end",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
}}
>
<AppText>{moment(date).format("h:mmA MMM Do YY")}</AppText>
</View>
</View>
</TouchableOpacity>
);
}
export default memo(NoteList);
I use these from flatlist, here is the main flatlist code:
export default function NoteListScreen() {
const [user, setUser] = useState<any>();
const nav = useNavigation();
// useEffect(() => {
// dispatch(loadDefault());
// }, []);
const dispatch: AppDispatch = useDispatch();
const data = useSelector((state: RootState) => state.persistedReducer.note);
const userInfo: user = useSelector(
(state: RootState) => state.persistedReducer.firebase.userInfomation
);
useEffect(() => {
dispatch(fetchNote(userInfo.email)); //fetch note from firebase
}, []);
return (
<SafeAreaView style={CONTAINER}>
{data.length === 0 ? (
<>
<ScrollView>
<HeaderNote />
<AppText style={EMPTY_NOTE}>
Hmm, so don't have any secret yet
</AppText>
</ScrollView>
<FooterNote />
</>
) : (
<View style={CONTAINER}>
<FlatList
removeClippedSubviews
data={data}
style={{
marginBottom:
Platform.OS === "ios"
? onePercentHeight * 15
: onePercentHeight * 12,
}}
keyExtractor={() => {
return (
new Date().getTime().toString() +
Math.floor(
Math.random() * Math.floor(new Date().getTime())
).toString()
);
}}
ListHeaderComponent={() => <HeaderNote />}
renderItem={({ item, index }) => {
return (
<NoteList ==> here , the note list that faced error
note={item.note}
title={item.header}
date={item.date}
id={item.id}
selectStatus={item.selectStatus}
/>
);
}}
/>
<FooterNote />
</View>
)}
</SafeAreaView>
);
}
Here is the reducer code:
const noteReducer = createSlice({
name: "note",
initialState: NoteList,
reducers: {
addNote: (state, action: PayloadAction<NoteI>) => {
const newNote: NoteI = {
id:
new Date().getTime().toString() +
Math.floor(
Math.random() * Math.floor(new Date().getTime())
).toString(),
header: action.payload.header,
note: action.payload.note,
date: new Date(),
selectStatus: false,
};
state.push(newNote);
},
toggleSelect: (state, action: PayloadAction<NoteI>) => {
return state.map((item) => {
if (item.id === action.payload.id) {
return { ...item, selectStatus: !item.selectStatus };
}
return item;
});
}, ///========>This is the reducer using in the note function
loadDefault: (state) => {
return state.map((item) => {
return { ...item, selectStatus: false };
});
},
resetNote: (state) => {
return (state = []);
},
editNote: (state, action: PayloadAction<NoteI>) => {
return state.map((item) => {
if (item.id === action.payload.id) {
return {
...item,
note: action.payload.note,
header: action.payload.header,
date: action.payload.date,
};
}
return item;
});
},
},
extraReducers: (builder) => {
builder.addCase(fetchNote.fulfilled, (state, action) => {
state = [];
return state.concat(action.payload);
});
},
});
Here is the image of what i'm talking about, the code in image from noteList.tsx, the first piece of code i post here
Here is the quick gif:
In above gif, the false must return true then false everytime i click ( as above code ) but i don't why it never change value, the black dot also change color because it use value using in the same function using with this value, but when setDeleteItem fire, it NOT fire the setDeleteChecked(!isDeleteChecked)
Here is the demo that i made, but it WORK TOTALLY FINE, but in my app, it make weird error https://codesandbox.io/s/nostalgic-neumann-0497v?file=/redux/some-redux.tsx
Please help, i'm trying to provide must as i can, i stuck for days for this, thank you so much, if you need any detail, just tell me

todos not loading while using AsyncStorage

I am trying to use AsyncStorage to fetch my todos from inside the useEffect hook. If there are no todos(Meaning todos === []) Then a Text Component shows saying "Add a todo".
App image in expo
Initially the todos are set to "[]" inside the useState hook. When the addItem() method is called onPress the todos are not loading.
I do not know why this is happening...
export default function App() {
const [todo, setTodo] = useState('');
const [todos, setTodos] = useState([]);
useEffect(() => {
_retrieveData();
}, [todos]);
const addItem = (newTodo) => {
if (newTodo.length === 0) {
Alert.alert(
'Enter a String',
'You have entered a string with 0 characters',
[{ text: 'Okay', style: 'default' }]
);
} else {
console.log(newTodo);
let newTodos = [newTodo, ...todos];
setTodo('');
_storeData(JSON.stringify(newTodos));
}
};
const deleteTodo = (idx) => {
setTodos(todos.filter((todo, id) => id !== idx));
};
const _storeData = async (value) => {
try {
await AsyncStorage.setItem('TASKS', value);
} catch (error) {
// Error saving data
console.log(e);
}
};
const _retrieveData = async () => {
try {
const value = await AsyncStorage.getItem('TASKS');
if (value !== null) {
// We have data!!
setTodos(JSON.parse(value));
console.log(value);
}
} catch (error) {
// Error retrieving data
console.log(error);
}
};
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={styles.outerContainer}>
<Text style={styles.header}>TODO</Text>
<View style={styles.container}>
<TextInput
placeholder='new todo'
style={styles.input}
value={todo}
onChangeText={(text) => {
setTodo(text);
}}
></TextInput>
<Button title='Add' onPress={() => addItem(todo)}></Button>
</View>
<ScrollView style={styles.scrollView}>
{todos === [] ? (
<View>
<Text>Add a todo!</Text>
</View>
) : (
todos.map((todo, idx) => (
<View style={styles.todo} key={idx}>
<Text style={styles.todoText}>{todo}</Text>
<View style={styles.delete}>
<Button
color='red'
title='Delete'
onPress={() => deleteTodo(idx)}
></Button>
</View>
</View>
))
)}
</ScrollView>
</View>
</TouchableWithoutFeedback>
);
}
Dont use passed todo value newTodo, as setState is async dont get executed immediately, so you can use current setted todo value instead passed old value,
const addItem = (newTodo) => {
if (todo.length === 0) {
Alert.alert(
'Enter a String',
'You have entered a string with 0 characters',
[{ text: 'Okay', style: 'default' }]
);
} else {
console.log(todo);
let newTodos = [todo, ...todos];
setTodo('');
_storeData(JSON.stringify(newTodos));
setTodos(newTodos);
}
};

react native : What is the way to populate the EmergencyRolePicker picker in data with a map function rather than hardcoded?

What is the way to populate the EmergencyRolePicker picker in data with a map function rather than hardcoded?
In my example I am trying to populate the picker but I want to do it with a map loop so I can select something from the picker.
The picker comes from the react-native-paper library.
I would be happy for some help with this issue.
this is my code:
import { List } from 'react-native-paper';
export const ActionsScreen = () => {
const [roleList, setRoleList] = useState([]);
useEffect(() => {
(async () => {
try {
// State table
const emcStateList: EmergencyStateType[] = await EmergencyStateTable.getEmergencyStateList();
console.log('emcStateList:', emcStateList.length);
let items = [];
emcStateList.forEach(function (item, i) {
items.push({ label: item.EmergencyName, value: item.EmergencyCode, key: i });
})
setStateList(items);
// Role table
const emcRoleList: EmergencyRoleType[] = await EmergencyRoleTable.getEmergencyRoleList();
console.log('emcRoleList:', emcRoleList.length);
items = [];
emcRoleList.forEach(function (item, i) {
items.push({ label: item.RoleName, value: item.RoleCode, key: i });
})
setRoleList(items);
//
} catch (error) {
console.log('A problem getting emergency list from db:', error);
}
})();
}, []);
const EmergencyRolePicker = () => {
return (
<List.Accordion title={roleList[0].label} id="0">
<List.Item title={roleList[1].label} />
<List.Item title={roleList[2].label} />
</List.Accordion>
)
}
return (
<>
<SafeAreaView style={styles.container}>
<ScrollView style={styles.scrollView}>
<View style={styles.text}>
<Text style={styles.label}>{MenuStrings.EmergencyRole}</Text>
<View style={styles.pickerView}>
<EmergencyRolePicker />
</View>
</View>
</ScrollView>
</SafeAreaView>
<View style={styles.BottomViewArea}>
<TouchableOpacity
style={{ alignSelf: 'flex-start', marginLeft: 60 }}
onPress={() => {
}}>
<Ionicons
name="send-sharp"
size={30}
color="white"
/>
</TouchableOpacity>
</View>
</>
);
}
this is the data:
[
{
"key":0,
"label":"red",
"value":1
},
{
"key":1,
"label":"green",
"value":2
},
{
"key":2,
"label":"yellow",
"value":3
}
]
Instead of the for loop, using the map as already mentioned by you would look like this:
let items = emcStateList.map((item, i) => ({
label: item.EmergencyName,
value: item.EmergencyCode,
key: i
})
setStateList(items);
As a sidenote, I would not use the index as a key, if the codes are unique, use those.
Also calling the endpoints one after another causes a waterwall. Instead try this:
const emcStateListPromise: Promise<EmergencyStateType[]> = EmergencyStateTable.getEmergencyStateList();
const emcRoleListPromise: Promise<EmergencyRoleType[]> = EmergencyRoleTable.getEmergencyRoleList();
const emcStateList = await emcStateListPromise
const emcRoleList = await emcRoleListPromise
Update:
useEffect(() => {
(async () => {
try {
// State table
const emcStateList: EmergencyStateType[] = await EmergencyStateTable.getEmergencyStateList();
let items = emcStateList.map((item, i) => ({
label: item.EmergencyName,
value: item.EmergencyCode,
key: i
}))
setStateList(items);
// Role table
const emcRoleList: EmergencyRoleType[] = await EmergencyRoleTable.getEmergencyRoleList();
console.log('emcRoleList:', emcRoleList.length);
items = emcRoleList.map((item, i) => ({
label: item.RoleName, value: item.RoleCode, key: i
}))
setRoleList(items);
//
} catch (error) {
console.log('A problem getting emergency list from db:', error);
}
})();
}, []);

Why adding extra state helps to update other state?

Here is the full code:
import * as React from 'react';
import { View, ScrollView, StyleSheet } from 'react-native';
import {
Appbar,
Searchbar,
List,
BottomNavigation,
Text,
Button,
} from 'react-native-paper';
const AccordionCollection = ({ data }) => {
var bookLists = data.map(function (item) {
var items = [];
for (let i = 0; i < item.total; i++) {
items.push(
<Button mode="contained" style={{ margin: 10 }}>
{i}
</Button>
);
}
return (
<List.Accordion
title={item.title}
left={(props) => <List.Icon {...props} icon="alpha-g-circle" />}>
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'flex-start',
backgroundColor: 'white',
}}>
{items}
</View>
</List.Accordion>
);
});
return bookLists;
};
const MusicRoute = () => {
const DATA = [
{
key: 1,
title: 'Zain dishes',
total: 21,
},
{
key: 2,
title: 'Sides',
total: 32,
},
{
key: 3,
title: 'Drinks',
total: 53,
},
{
key: 4,
title: 'Aesserts',
total: 14,
},
];
const [data, setData] = React.useState(DATA);
const [searchQuery, setSearchQuery] = React.useState('');
const [sortAZ, setSortAZ] = React.useState(false);
const onChangeSearch = (query) => {
setSearchQuery(query);
const newData = DATA.filter((item) => {
return item.title.toLowerCase().includes(query.toLowerCase());
});
setData(newData);
};
const goSortAZ = () => {
setSortAZ(true);
setData(
data.sort((a, b) => (a.title > b.title ? 1 : b.title > a.title ? -1 : 0))
);
};
const goUnSort = () => {
setSortAZ(false);
setData(DATA);
};
return (
<View>
<Appbar.Header style={styles.appBar}>
<Appbar.BackAction onPress={() => null} />
<Searchbar
placeholder="Search"
onChangeText={onChangeSearch}
value={searchQuery}
style={styles.searchBar}
/>
<Appbar.Action
icon="sort-alphabetical-ascending"
onPress={() => goSortAZ()}
/>
<Appbar.Action icon="library-shelves" onPress={() => goUnSort()} />
</Appbar.Header>
<ScrollView>
<List.Section title="Accordions">
<AccordionCollection data={data} />
</List.Section>
</ScrollView>
</View>
);
};
const AlbumsRoute = () => <Text>Albums</Text>;
const MyComponent = () => {
const [index, setIndex] = React.useState(0);
const [routes] = React.useState([
{ key: 'music', title: 'Music', icon: 'queue-music' },
{ key: 'albums', title: 'Albums', icon: 'album' },
]);
const renderScene = BottomNavigation.SceneMap({
music: MusicRoute,
albums: AlbumsRoute,
});
return (
<BottomNavigation
navigationState={{ index, routes }}
onIndexChange={setIndex}
renderScene={renderScene}
/>
);
};
const styles = StyleSheet.create({
appBar: {
justifyContent: 'space-between',
},
searchBar: {
width: '60%',
shadowOpacity: 0,
borderRadius: 10,
backgroundColor: '#e4e3e3',
},
});
export default MyComponent;
Expo Snack Link
There are two weird mechanisms.
First
If I remove sortAZ(true) in goSortAZ() and sortAZ(false) in goUnSort(), the state data stops updating after you press on (1) sort and (2) unsort buttons more than three times.
Second
If I remove DATA array outside the component, sort and unsort buttons does not work/update.
If I do not remove these two, I can sort and unsort the list.
I feel that the code is messy although it achieves the function.
My questions is:
Why adding extra state (sortAZ) helps to update other state (data)?
Just totally remove sortAZ variable (no need to use it unless you somehow want to have a loading status, but since you are not making http requests, that's not necessary) and replace goSortAZ with the following:
Remember to clone the original array in order to create a new copy and then sort that copy.
This is working fine.
const goSortAZ = () => {
setData(
[...data].sort((a, b) => (a.title > b.title ? 1 : b.title > a.title ? -1 : 0))
);
};
i would suggest using the same technique for the unSort method too.

Categories

Resources