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?
Related
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.
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>
I am using react-native-sortable-listview in react-native for sorting same places.
constructor() {
this.state = {
makers: [
{ kolkata: 'Hawrah Birdge' },
{ Delhi: 'Lal Kila' },
{ Agra: 'Taj Mahal' },
{ Mumbai: 'India Gate' },
],
allObj: {},
order: []
};
}
componentDidMount() {
const newAllObj = this.getAllObjFromMaker(this.state.makers);
const newOrder = this.getOrderFromMaker(newAllObj);
this.setState({ allObj: newAllObj, order: newOrder });
}
getAllObjFromMaker(makers) {
const allObj = makers.reduce((result, d) => {
result[`${d.coordinate.latitude}_${d.coordinate.longitude}`] = d;
return result;
}, {});
return allObj;
}
getOrderFromMaker(allObj) {
const order = Object.keys(allObj);
return order;
}
renderOneDraggableMilestone(milestone) {
const i = this.state.makers.indexOf(milestone);
return (
<TouchableOpacity {...this.props.sortHandlers}>
<Text>{i + 1}</Text>
<Text>{milestone.address}</Text>
</TouchableOpacity>
);
}
arrangedMilestoneList(e) {
const arr = this.state.makers;
arr.splice(e.to, 0, arr.splice(e.from, 1)[0]);
const newAllObj = this.getAllObjFromMaker(arr);
const newOrder = this.getOrderFromMaker(newAllObj);
this.setState({ makers: arr, allObj: newAllObj, order: newOrder
});
}
render() {
return (
<SortableListView
data={this.state.allObj}
order={this.state.order}
activeOpacity={0.5}
onRowMoved={e => {
this.arrangedMilestoneList(e);
this.forceUpdate();
}}
renderRow={(row) => this.renderOneDraggableMilestone(row)}
/>
);
}
I want to arrange places and also their position in this.state.makers as I am doing using i in renderOneDraggableMilestone. On renderRow only draggable place are render so only their position is updated. And renderRow is last to excute so forceUpdate is also not working.
How to rerender after executing renderRow. So all position could be updated.
Ok I have find a way to re-render as follow.
<SortableListView
key={this.state.count}
data={this.state.allObj}
order={this.state.order}
activeOpacity={0.5}
onRowMoved={e => {
this.setState({ count: this.state.count + 1 });
this.props.arrangedMilestoneList(e);
console.log('onRowMoved is called');
}}
onMoveEnd={() => console.log('onMoveEnd is fired')}
renderRow={(row, s1, i) => this.renderOneDraggableMilestone(row, s1, i)}
/>
What I am doing is I added a key attribute to SortableListView and update this key on each onRowMoved action. And because of this it causes re-render.
I'm using https://github.com/gcanti/tcomb-form-native
& here's the snippet of code
_renderScene(route, navigator) {
var Cook_time = {
onFocus: () => {
console.log('cook time has focus');
console.log(this.refs);
},
};
options.fields['Cook_time'] = Cook_time;
return (
<View style={{ flex: 1 }}>
<ScrollView style={styles.container} ref="scrollView">
<Form
ref="form"
type={Recipe}
options={options}
onChange={this.onChange}
onFocus={this.onChange}
/>
console.log prints object{} when it should refer to scrollView, not sure what I might be missing. And here's the code that sets up the form itself
var Recipe = t.struct({
Recipe_name: t.String,
yield: t.maybe(t.String),
Prep_time: t.maybe(t.String),
Cook_time: t.maybe(t.String),
source: t.maybe(t.String),
})
var options = {
fields: {
yield: {
label: 'Yield',
},
Prep_time: {
label: 'Preparation time',
},
source: {
label: 'Source',
placeholder: 'family, friends, website ...',
onFocus: function () {
console.log('source has focus');
}
}
}
};
ref attribute is a callback and as per react-native documentation
all I need to do is save a reference as so
<ScrollView style={styles.container} ref={(ref) => this.myScrollView = ref}>