how to handle nested object with map for display on flatlist or text or other component at react native. i tried to display using text and flatlist but didnt work, i want to display like this
this is my code,
const Schedule = () => {
const [resp, setData] = useState([]);
useEffect(() => {
const fetchData = async () => {
const respData1 = await axios(
`http://sh3ll.my.id/api/data3.json`
);
setData({ data: respData1.data.data });
};
fetchData();
},[]);
console.log('render');
if (resp.data) {
console.log("d==>", resp);
}
return (
<View style={{paddingTop:20}}>
{ resp.data && resp.data.map((items,i)=>
<Text key={i}>{`${items.date} ${items.time}`}
{items.list.map((sub)=>{ `${sub.description}`
})}
</Text>
) }
{/* <FlatList data={resp}
keyExtractor={(x,i)=>i}
renderItem={({item})=>
....?? }
/> */}
</View>
)
}
export default Schedule
Looking at your code, I assume your data object looks like this:
const resp = {
data: [
{
date: "date 1",
time: "time 1",
list: [{ description: "desc 1" }, { description: "desc 2" }]
},
{
date: "date 2",
time: "time 2",
list: [{ description: "desc 1" }, { description: "desc 2" }]
}
]
};
If that's correct, you can flatten your object by calling your own "createDescription" function that will take care of rendering the descriptions:
function createDescription(listItem) {
return <p>{listItem.description}</p>;
}
return (
<table style={{ paddingTop: 20 }}>
{resp.data &&
resp.data.map((items, i) => (
<tr key={i}>
<td>{items.date}</td>
<td>{items.time}</td>
<td>{items.list.map((sub) => createDescription(sub))}</td>
</tr>
))}
</table>
);
Now that you have your HTML correctly rendered, you can fix the layout using CSS.
Related
I have a array:
const data: arrdata[] = [
{ iD: "55", tP: "01" },
{ iD: "3f", tP: "00" },
{ iD: "fe", tP: "00" },
];
and want update app page after I change tP value in other app page. Also I am using reactnative navigator. For array rendering I am using map()
I try use useEffect hook (it works if using this hook like timeout update, but this variant have issue - all my modals closing if I try open them). Can someone explain how I should rerender my app page?
Here my code First Page:
interface dTtypes {
iD: string;
tP: string;
}
const moduliaiDT: dTtypes[] = [
{ iD: "55", tP: "01" },
{ iD: "3f", tP: "00" },
{ iD: "fe", tP: "00" },
];
function StackasScreen({ navigation }: { navigation: any }) {
const [moduliaiData, setModuliaiData] = useState(moduliaiDT);
const navigacijosMyktukai = (
moduliaiDT: dTtypes[],
setModuliaiData: React.Dispatch<React.SetStateAction<any[]>>
) => {
navigation.navigate("PageB", { moduliaiDT, setModuliaiData });
};
const testasUpdatui = () => {
if (moduliaiDT.length == 3) {
moduliaiDT.push({ iD: "91", tP: "05" });
} else if (moduliaiDT.length == 4) {
moduliaiDT.push({ iD: "92", tP: "05" });
}
setModuliaiData([...moduliaiDT]);
};
return (
<View style={styles.body}>
<Text>{moduliaiDT.length}</Text>
{moduliaiData.map((modulis) => {
return (
<View style={styles.item} key={modulis.iD}>
<Text style={styles.tekstas}>
ID:{modulis.iD}, Type:{modulis.tP}
</Text>
</View>
);
})}
<Button onPress={() => testasUpdatui()} title="Add" />
<Button
onPress={() => navigacijosMyktukai(moduliaiDT, setModuliaiData)}
title="go page B"
/>
</View>
);
}
And page B:
export default function TestingScreen({
navigation,
route,
}: {
navigation: any;
route: any;
}) {
const { moduliaiDT, setModuliaiData } = route.params;
const [moduliaiDatas, setModuliaiDatas] = useState(moduliaiDT);
const navigacijosMyktukai = (moduliaiDT: any) => {
navigation.navigate("PageA", { moduliaiDT });
setModuliaiData(moduliaiDatas);
};
const testasUpdatui = () => {
//setModuliaiDatas([...moduliaiDatas, {iD: '90', tP: '04'}]);
//moduliaiDT.push({iD: '90', tP: '04'});
if (moduliaiDT.length == 4) {
moduliaiDT[3] = { iD: "44", tP: "08" };
} else if (moduliaiDT.length == 5) {
moduliaiDT[4] = { iD: "45", tP: "09" };
}
setModuliaiDatas([...moduliaiDT]);
};
return (
<View style={styles.body}>
<Text>TestScreen</Text>
{moduliaiDatas.map(
(modulis: {
iD: React.Key | null | undefined;
tP:
| string
| number
| boolean
| React.ReactElement<any, string | React.JSXElementConstructor<any>>
| React.ReactFragment
| React.ReactPortal
| null
| undefined;
}) => {
return (
<View style={styles.item} key={modulis.iD}>
<Text style={styles.tekstas}>
ID:{modulis.iD}, Type:{modulis.tP}
</Text>
</View>
);
}
)}
<Button onPress={() => testasUpdatui()} title="Change data" />
<Button onPress={() => navigacijosMyktukai(moduliaiDT)} title="Go back" />
</View>
);
}
in page B i get error :
Non-serializable values were found in the navigation state
I found solution for this error:
import { LogBox } from "react-native";
LogBox.ignoreLogs([
"Non-serializable values were found in the navigation state",
]);
This code working but maybe is better solution?
I have a flatlist in react-native and I am trying to refetch the data when pulling it down (the native refresh functionality). When I do, I am getting this error:
Typeerror: undefined is not an object
I can't figure out what is going wrong. I am using
Expo SDK 38
"#apollo/client": "^3.1.3",
"graphql": "^15.3.0",
This is my code:
export default function DiscoverFeed({ navigation }) {
const theme = useTheme();
const { data, error, loading, refetch, fetchMore, networkStatus } = useQuery(
GET_RECIPE_FEED,
{
variables: { offset: 0 },
notifyOnNetworkStatusChange: true,
}
);
if (error) return <Text>There was an error, try and reload.</Text>;
if (loading) return <Loader />;
if (networkStatus === NetworkStatus.refetch) return <Loader />;
const renderItem = ({ item }) => {
return (
<View style={styles.cardItems}>
<RecipeCard item={item} navigation={navigation} />
</View>
);
};
return (
<SafeAreaView style={styles.safeContainer} edges={["right", "left"]}>
<FlatList
style={styles.flatContainer}
data={data.recipe}
removeClippedSubviews={true}
renderItem={renderItem}
refreshing={loading}
onRefresh={() => {
refetch();
}}
keyExtractor={(item) => item.id.toString()}
onEndReachedThreshold={0.5}
onEndReached={() => {
// The fetchMore method is used to load new data and add it
// to the original query we used to populate the list
fetchMore({
variables: {
offset: data.recipe.length,
},
});
}}
/>
</SafeAreaView>
);
}
I have a typepolicy like so:
export const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
recipe: {
merge: (existing = [], incoming, { args }) => {
// On initial load or when adding a recipe, offset is 0 and only take the incoming data to avoid duplication
if (args.offset == 0) {
console.log("offset 0 incoming", incoming);
return [...incoming];
}
console.log("existing", existing);
console.log("incoming", incoming);
// This is only for pagination
return [...existing, ...incoming];
},
},
},
},
},
});
And this is the query fetching the data:
export const GET_RECIPE_FEED = gql`
query GetRecipeFeed($offset: Int) {
recipe(order_by: { updated_at: desc }, limit: 5, offset: $offset)
#connection(key: "recipe") {
id
title
description
images_json
updated_at
dishtype
difficulty
duration
recipe_tags {
tag {
tag
}
}
}
}
`;
I am building a food delivery application, and I would like to know how I can limit the number of checkboxes selected. An example is when entering the subsidiary, it displays a list of products. If I select a pizza, there is an extras section that limits the number of extras you can select, if you want to select more than two and your limit is two it should not allow you
all this with react hooks, I attach a fragment of my component
const ExtrasSelector = ({options = [{}], onPress = () => {}, limit = 0}) => {
const [showOptions, setShowOptions] = useState(true);
const [selectedAmount, setSelectedAmount] = useState(0);
const EXTRA = ' extra';
const EXTRAS = ' extras';
const updatedList = options.map(data => ({
id: data.id,
name: data.name,
price: data.price,
selected: false,
}));
const [itemsList, setItemsList] = useState(updatedList);
const toggleOptions = () => setShowOptions(!showOptions);
useEffect(() => {
}, [selectedAmount]);
// onPress for each check-box
const onPressHandler = index => {
setItemsList(state => {
state[index].selected = !state[index].selected;
onPress(state[index], getSelectedExtras(state));
// Increments or decreases the amount of selected extras
if (state[index].selected) {
setSelectedAmount(prevState => prevState + 1);
} else {
setSelectedAmount(prevState => prevState - 1);
}
return state;
});
};
const getSelectedExtras = extrasArr => {
const selectedExsArr = [];
extrasArr.map(item => {
if (item.selected) {
selectedExsArr.push(item);
}
});
return selectedExsArr;
};
return (
<View>
<View style={styles.container}>
<TouchableOpacity style={styles.row} onPress={toggleOptions}>
<Text style={styles.boldTitleSection}>
Extras {'\n'}
<Text style={titleSection}>
Selecciona hasta {limit}
{limit > 1 ? EXTRAS : EXTRA}
</Text>
</Text>
<View style={styles.contentAngle}>
<View style={styles.contentWrapperAngle}>
<Icon
style={styles.angle}
name={showOptions ? 'angle-up' : 'angle-down'}
/>
</View>
</View>
</TouchableOpacity>
{showOptions ? (
itemsList.map((item, index) => (
<View key={index}>
<CheckBox
label={item.name}
price={item.price}
selected={item.selected}
otherAction={item.otherAction}
onPress={() => {
onPressHandler(index, item);
}}
/>
<View style={styles.breakRule} />
</View>
))
) : (
<View style={styles.breakRule} />
)}
</View>
</View>
);
};
This is a simple react implementation of "checkboxes with limit" behaviour with useReducer. This way the business logic (here the limitation but can be any) is implemented outside of the component in a pure js function while the component itself is just a simple reusable checkbox group.
const { useReducer } = React; // --> for inline use
// import React, { useReducer } from 'react'; // --> for real project
const reducer = (state, action) => {
if (state.checkedIds.includes(action.id)) {
return {
...state,
checkedIds: state.checkedIds.filter(id => id !== action.id)
}
}
if (state.checkedIds.length >= 3) {
console.log('Max 3 extras allowed.')
return state;
}
return {
...state,
checkedIds: [
...state.checkedIds,
action.id
]
}
}
const CheckBoxGroup = ({ data }) => {
const initialState = { checkedIds: [] }
const [state, dispatch] = useReducer(reducer, initialState)
return (
<table border="1">
{data.map(({ id, label }) => (
<tr key={id}>
<td>
<input
onClick={() => dispatch({ id })}
checked={state.checkedIds.includes(id)}
type="checkbox"
/>
</td>
<td>
{label}
</td>
</tr>
))}
</table>
)
};
const data = [
{ id: "1", label: "Mashroom" },
{ id: "2", label: "Ham" },
{ id: "3", label: "Egg" },
{ id: "4", label: "Ananas" },
{ id: "5", label: "Parmesan" },
]
ReactDOM.render(<CheckBoxGroup data={data} />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
How can I separate the data to make my section list look like how it is in the picture?
https://i.stack.imgur.com/oABMf.png
It depends on the data structure you have. Lets assume you have this kind of data structure:
const data = [
{
id: 1,
text: "Fooo text 1",
description: "Foooo description 1"
},
{
id: 2,
text: "Fooo text 2",
description: "Foooo description 2"
},
]
function ListScreen() {
const sections = []
sections.push({ title: 'Title', data: data });
return (
<SectionList
sections={sections}
renderItem={({ item, index }) => <Text>{item.id}</Text>}
renderSectionHeader={SectionHeader}
keyExtractor={(item, index) => item.id.toString()}
/>
);
}
function SectionHeader({ section: { title } }) {
return (
<View style={styles.sectionHeader}>
<Text>{title}</Text>
</View>
);
}
const styles = StyleSheet.create({
sectionHeader: {
padding: 12,
},
});
I am trying to display same screen with different parameter in react-native. i checked with https://snack.expo.io/#react-navigation/navigate-with-params-v3. its working fine. But i have to display the different data in same screen. My expectation is in tree view structure data have to display like in our normal system tile view folder structure.
Expected Output view:
The view like normal our system folder title structure. C:/user/ReactNative/file .. like tile view.
Ex:
1.FamilyScreen.js
params : Gradpa -> while click Grandpa it will navigate to same page but the data change as 'Father'
FamilyScreen.js
params:Me - While click 'Father' it will navigate to same page but the data as 'Erick and Rose'.
The data will come from service so it may contain some more than children. it will variant. How to pass the particular data in react-native.
const family = [
{
id: 'Grandparent',
name: 'Grandpa',
age: 78,
children: [
{
id: 'Father',
name: 'Father',
age: 30,
children: [
{
id: 'Erick',
name: 'Erick',
age: 10,
},
{
id: 'Rose',
name: 'Rose',
age: 12,
},
],
},
],
},
]
Thanks
Finaly its working, here my code is
constructor(props) {
super(props)
this.state = {
res:family,
}
this.getNestedData = this.getNestedData.bind(this);
}
getNestedData (item) {
var data;
Object.keys(item).map((propKey) => {
if ( propKey === 'children'){
data=item[propKey]
}
})
this.props.navigation.push('GridScreen',{
data:data
});
}
Item = ({ item }) => {
return (
<View style={styles.item}>
<Text style={styles.title} onPress={this.getNestedData.bind(this,item)}>{item.name}</Text>
</View>
);
}
render() {
const { navigation } = this.props;
const data = navigation.getParam('data', this.state.res);
return (
<View>
<FlatList
data={data }
renderItem={({ item }) => <this.Item item={item} />}
keyExtractor={item => item.id}
numColumns={3}
/>
</View>
)
}
}