Change switch value without change all of them - javascript

I'm a beginner and I don't know how to change switch value without change all of them. You can see the code about. I'm mapping a nested array on return. I'm confuse how to change the switch status individually. I've tried some solutions like change the value inside the array with an onchange event but it doenst reender the screen.
const [dtData, setDtData] = useState('release_data');
useFocusEffect(
React.useCallback(() => {
getManagerListDay(function(resultado) {
setDtData(resultado);
});
setInterval(() => {
getManagerListDay(function(resultado) {
setDtData(resultado);
});
toasted.showToast('Refresh');
}, 60000);
}, [])
);
const section = [];
for ( var i = 0, ii = dtData.length; i < ii; i++ ) {
if(i>0?dtData[i].dayDate != dtData[i-1].dayDate:true == true){
const items = [];
for ( var b = 0, bb = dtData.length; b < bb; b++ ) {
if(dtData[b].dayDate == dtData[i].dayDate){
items.push({
name: dtData[b].name,
worked: dtData[b].worked,
workedWeekDays: dtData[b].workedWeekDays,
KeyItemDriver: dtData[b].KeyItemDriver
});
}
}
section.push({
dayDate: dtData[i].dayDate,
driverAmount: dtData[i].driverAmountAccepted,
keySectionDay: dtData[i].keySectionDay,
data: items
});
}
}
return (
<Root>
<View style={{marginTop:15}}>
{section.map((obj, index) => {
return(
<List.Section
title={obj.dayDate}
titleStyle={{color:'black',fontWeight:'bold', fontSize: 16}}
style={{backgroundColor:'rgba(79,79,79,0.1)', marginTop:0, borderRadius:30, width:'90%',alignSelf:'center'}}
key={index}
id={obj.keySectionDay} >
<Button mode="contained" style={{borderRadius:70,width:40,backgroundColor:'#48D1CC', marginLeft:'80%'}}>
<Text style={{fontWeight:'bold', marginRight:50}}> {obj.driverAmount} </Text> </Button>
<FAB style={styles.fab} color='white' small={false} icon="database-export" onPress={() => console.log('Pressed')} />
<List.Accordion
title="DRIVERS"
key={index}
theme={{ colors: { primary: '#48D1CC' }}}
titleStyle={{color:'black', fontSize:14}}
left={props => <List.Icon {...props} icon="folder"/>}>
{obj.data.map((dts,index) => {
return(
<List.Item key={index} id={dts.KeyItemDriver} title={dts.name} titleStyle={{color:'black'}}
style={{borderTopColor:'white', borderTopWidth:1}}
left={props => <Switch {...props} color={dts.worked=='S'?'#48D1CC':'red'} value={dts.worked!=null?true:false}/>}
right={props => <Text {...props} style={{color:'#48D1CC',fontSize:18, marginTop:5}} > {dts.workedWeekDays} </Text>}
onPress={() => alert('Sou eu')}
/>
)
})}
</List.Accordion>
</List.Section>
);
})
}
</View>
</Root>
);

Never mind! I was thinking wrong about the steps process. I need.
I just update the information on the database and rerender the screen from there. What I think is correct. I must show what is commited.
Thanks!

Related

Accordion inside a Flatlist React native

I have an accordion inside a flatlist.
Here is the code i have :
const OptionList = (groupOption) => {
return (
<FlatList
data={groupOption.options}
keyExtractor={(result) => result.id.toString()}
renderItem={({ item, index }) => {
const clickedRadio = () => {
const selectedOption = { [item.question]: { ...item } };
setAnswers({ ...answers, ...selectedOption });
};
const status = isOptionSelected(item) ? true : false;
return (
<View key={index}>
<Radio
initialValue={status}
label={item.description}
onChange={() => clickedRadio()}
color="error"
/>
</View>
);
}}
/>
);
};
return (
<View style={styles.container}>
<Text style={{ fontWeight: "bold", fontSize: 16, color:"#6B24AA" }}>
{t("Choose an option/Scroll for more questions")}
</Text>
<FlatList
data={questions}
listKey={(item) => item.id.toString()}
keyExtractor={(result) => result.id.toString()}
renderItem={({ item, index }) => {
const data = [
{
title: item.description,
content: (<><OptionList options=
{item?.question_options}></OptionList></>)
}
];
const status = isOptionSelected(item) ? true : false;
return (
<View style={styles.groupOptions} key={index}>
<Accordion style={styles.accordion}
headerStyle=
{styles.headerStyle} contentStyle={styles.contentStyle}
dataArray={data}
icon={status ? <Icon name="circle"
family="Entypo" size={20} style={{marginLeft: -6,
color: "#6B24AA"}}/>
:
<Icon name="done"
family="MaterialIcons" size={20}
style={{marginLeft: -6}}/>}
expandedIcon={<Icon name="circle"
family="Entypo"/>}
opened={1}/>
</View>
);
}}
/>
</View>
);
The accordion content its anther flatlist component. It shows this error every time i click the accordion.
It shows this error :
VirtualizedList: Encountered an error while measuring a list's offset from its containing VirtualizedList.
at node_modules/react-native/Libraries/Lists/VirtualizedList.js:1411:10 in _scrollRef.measureLayout$argument_2
How can i fix this error? Is it the problem the other flatlist at the content of accordion
Please replace the OptionList component with the given below code.
OptionList
const OptionList = (groupOption) => {
return (
groupOption.map((item,index) => {
const clickedRadio = () => {
const selectedOption = { [item.question]: { ...item } };
setAnswers({ ...answers, ...selectedOption });
};
const status = isOptionSelected(item) ? true : false;
return (
<View key={index}>
<Radio
initialValue={status}
label={item.description}
onChange={clickedRadio}
color="error"
/>
</View>
)
})
);
};
please check and let me know , cheers !

Is there a way to use a map inside of another map function?

What I'm trying to do is after a field name, I want to render its type which is in another state as you can see:
my code:
const FormScreen = ({route}) => {
const [FieldForm, setFieldForm] = useState([]);
const [TypeForm, setTypeForm] = useState([]);
useEffect(() => {
if (userForm.length > 0) {
return;
} else {
setFieldForm(JSON.parse(route.params.paramKey).fields);
setTypeForm(JSON.parse(route.params.paramKey).type);
console.log(FieldForm,TypeForm); // returns me: {"message":["ab","test"],"tipo":["Date","Text"]}
}
},[userForm,TypeForm]);
return (
<SafeAreaView style={{flex: 1}}>
<View>
<Text>COLLECTION :</Text>
{FieldForm.length > 0 ? (
FieldForm.map((item) => (
<Text key={uuid.v4()}>{item}</Text>
//Here I want to to map which type is the field(to use conditionals to render) but how can I make it?
))
) : (
<Text key={uuid.v4()}> Loading ...</Text>
)}
</View>
</SafeAreaView>
);
};
How can I use a map inside of a map to do it, or creating an api call to return the type of the fields?
You can definitely nest the map functions :
const FormScreen = ({route}) => {
const [FieldForm, setFieldForm] = useState([]);
const [TypeForm, setTypeForm] = useState([]);
useEffect(() => {
if (userForm.length > 0) {
return;
} else {
setFieldForm(JSON.parse(route.params.paramKey).fields);
setTypeForm(JSON.parse(route.params.paramKey).type);
console.log(FieldForm,TypeForm); // returns me: {"message":["ab","test"],"tipo":["Date","Text"]}
}
},[userForm,TypeForm]);
return (
<SafeAreaView style={{flex: 1}}>
<View>
<Text>COLLECTION :</Text>
{FieldForm.length > 0 ? (
FieldForm.map((item) => (
<>
<Text key={uuid.v4()}>{item}</Text>
<> {TypeForm.length && TypeForm.map((type) => ( // Return node )) || null};
</>
</>
))
) : (
<Text key={uuid.v4()}> Loading ...</Text>
)}
</View>
</SafeAreaView>
);
};

unique "key" prop error using RN FlatList with List ITem

I have a screen in which I display a list of products.
I am trying to set up a pagination. I am using List item from react-native-elements and looking at Using RN FlatList as possible in the documentation for this package.
I set up the ability to do pagination, but I got confused in my code. I don't know how to fix it anymore. I would like to know if it would be possible for you to give me a boost and reread my code to give me your opinion.
There for the moment I have the error:
Each child in a list should have a unique "key" prop
I'm a bit lost and need some guidance please. Thanks for any explanation.
The code :
export default class Products extends Component {
constructor(props) {
super(props);
this.state = {
productId: (props.route.params && props.route.params.productId ? props.route.params.productId : -1),
listData: '',
currentPage: 1,
loadMoreVisible: true,
loadMoreVisibleAtEnd: false,
displayArray: []
}
};
initListData = async () => {
let list = await getProducts(1);
if (list) {
this.setState({
displayArray: list,
loadMoreVisible: (list.length >= 10 ? true : false),
currentPage: 2
});
}
};
setNewData = async (page) => {
let list = await getProducts(parseInt(page));
if (list) {
this.setState({
displayArray: this.state.displayArray.concat(list),
loadMoreVisible: (list.length >= 10 ? true : false),
loadMoreVisibleAtEnd: false,
currentPage: parseInt(page)+1
});
}
};
loadMore() {
this.setNewData(this.state.currentPage);
}
displayBtnLoadMore() {
this.setState({
loadMoreVisibleAtEnd: true
});
}
async UNSAFE_componentWillMount() {
this.initListData();
}
renderItem = ({ item, i }) => (
<ListItem key={i}
bottomDivider
containerStyle={{backgroundColor: i % 2 === 0 ? '#fde3a7' : '#fff' }}
onPress={() => this.props.navigation.navigate('ProductDetails', {productId:parseInt(item.id)})}>
<Icon name='shopping-cart' />
<ListItem.Title style={{width: '65%', fontSize: 14, color: i % 2 === 0 ? '#212121' : '#F78400' }}>{item.name}</ListItem.Title>
<ListItem.Subtitle style={{ color: '#F78400'}}>{i18n.t("information.cost")}:{item.cost}</ListItem.Subtitle>
</ListItem>
);
render() {
//console.log('displayArray', this.state.displayArray)
return (
<View style={{flex: 1}}>
{this.state.displayArray !== null && this.state.displayArray.length > 0 ? (
<View style={{ flex: 1}}>
<SafeAreaView>
{
this.state.displayArray.map((item, i) => (
<FlatList
keyExtractor={(item, i) => {
return item.id;
}}
data={this.state.displayArray}
onEndReached={() => this.displayBtnLoadMore()}
renderItem={this.renderItem}
/>
))
}
</SafeAreaView>
{this.state.loadMoreVisible === true && this.state.loadMoreVisibleAtEnd === true ? (
<Button title=" + " onPress={()=>{this.loadMore()}}></Button>
) : null
}
<View style={styles.container}>
<Text>{"\n"}</Text>
<TouchableOpacity
style={styles.touchable2}
onPress={() => this.props.navigation.goBack()}
>
<View style={styles.container}>
<Button
color="#F78400"
title= 'Back'
onPress={() => this.props.navigation.goBack()}>BACK
</Button>
</View>
</TouchableOpacity>
</View>
<Text>{"\n\n"}</Text>
</View>
) : (
<View style={styles.container}>
<Text>{"\n\n" + (this.state.displayArray === null ? i18n.t("products.searching") : i18n.t("products.nodata")) + "\n\n\n"}</Text>
<Button
color="#F78400"
title= 'Back'
onPress={() => this.props.navigation.goBack()}>BACK
</Button>
</View>
)}
</View>
);
};
}
The problem is not in your list items but in the FlatList itself - you are rendering an array of FlatList components but they don't have unique keys.
this.state.displayArray.map((item, i) => (
<FlatList
key={item.id} // or key={i} if item doesn't have ID
... rest of your flat list props
/>
))

How to Dynamically create checkboxes in React-Native

function Screen() {
const [lvls, setLvls] = React.useState([]);
const [done, setDone] = React.useState(null);
const [toggleCheckBox, setToggleCheckBox] = React.useState(false)
React.useEffect(() => {
async function checkData() {
const data = await AsyncStorage.getAllKeys();
setLvls(data);
}
checkData();
setDone(true);
}, []);
return (
<View>
{done && (lvls.length) ? (
lvls.map((element, i) => {
return (
<View key={i} style={{flexDirection: 'row'}}>
<CheckBox
disabled={false}
value={toggleCheckBox}
onValueChange={(newValue) => setToggleCheckBox(newValue)}
/>
<Text style={styles.text}>{lvls[i]}</Text>
</View>)
})
):
(
<Text style={styles.emptyText}>NO</Text>
)}
</View>
);
}
My aim is to dynamically render a checkbox that corresponds to each element in lvls.
I am currently doing that, however all of the checkboxes share the same state toggleCheckbox.
How can I create unique states for each checkbox according to lvls?
You can create a object that will store all the checkboxes values.
const [toggleCheckBox, setToggleCheckBox] = React.useState({})
<CheckBox
disabled={false}
value={toggleCheckBox[i] ? true : false}
onValueChange={() =>
setToggleCheckBox({
...toggleCheckBox,
[i] : !toggleCheckBox[i]
})}
/>
Placing into your code...
function Screen() {
const [lvls, setLvls] = React.useState([]);
const [done, setDone] = React.useState(null);
const [toggleCheckBox, setToggleCheckBox] = React.useState({})
React.useEffect(() => {
async function checkData() {
const data = await AsyncStorage.getAllKeys();
setLvls(data);
}
checkData();
setDone(true);
}, []);
return (
<View>
{done && (lvls.length) ? (
lvls.map((element, i) => {
return (
<View key={i} style={{flexDirection: 'row'}}>
<CheckBox
disabled={false}
value={toggleCheckBox[i] ? true : false}
onValueChange={() =>
setToggleCheckBox({
...toggleCheckBox,
[i] : !toggleCheckBox[i]
})}
/>
<Text style={styles.text}>{lvls[i]}</Text>
</View>)
})
):
(
<Text style={styles.emptyText}>NO</Text>
)}
</View>
);
}

How to take array values within json data in react native?

Hello I'm trying to render a fetch response from server like the following
.then(responseData => {
responseData.map(detail => {
let currIndex = -1;
let k = detail.data.curriculum.reduce((acc, curr) => {
if (curr.type === 'section') {
acc.push({
title: curr.title,
content: [],
id: []
})
currIndex += 1
} else {
acc[currIndex].content.push(curr.title);
acc[currIndex].id.push(curr.id);
}
return acc;
}, []);
console.log(k)
this.setState({ k })
});
});
I'm trying to render a UI like this
But what I'm getting is the name of video contents will be listed one after the other as a list like this
The corresponding code I've tried so far is as below
code
<Content padder style={{ backgroundColor: "#f4f4f4" }}>
{this.state.k.map(detail =>
<View style={st.card}>
<View style={st.cardHeading}>
<Text style={st.headingText}>{detail.title}</Text>
</View>
<ScrollView
horizontal
style={st.cardBody}>
<View style={st.videoContent}>
<View style={st.videoImage}>
<MaterialCommunityIcons name="play-circle-outline" size={25} color="#fff" />
</View>
<Text style={st.subheadingText}>{detail.content}</Text>
</View>
</ScrollView>
</View>
)}
</Content
>
The json data within this.state.k is as follows.I'm trying to render the Title as headingText and content as videoContent.Please help me to find a solution.
It looks like what you are missing is to actually loop through the content or id arrays inside the ScrollView element. Based on your current data structure, I would suggest doing something like this.
<ScrollView
horizontal
style={st.cardBody}
>
{detail.content.map((contentValue, i) => (
<View style={st.videoContent}>
<View style={st.videoImage}>
<MaterialCommunityIcons
name="play-circle-outline"
size={25}
color="#fff"
/>
</View>
<Text style={st.subheadingText}>
Title: { contentValue }
Id: { detail.id[i] }
</Text>
</View>
))}
</ScrollView>
Note that I added the value from the id array inside the Text element, both to illustrate how to access it, but also to show that the data structure makes this quite cumbersome so it might be better to improve that structure, possible like this
.then(responseData => {
responseData.map(detail => {
let currIndex = -1;
const k = detail.data.curriculum.reduce((acc, curr) => {
if (curr.type === 'section') {
acc.push({
title: curr.title,
content: []
})
currIndex += 1
} else {
acc[currIndex].content.push(curr);
}
return acc;
}, []);
this.setState({ k })
});
});
That way you don't have to keep track of the index of the array when mapping and can simple use it like this
{detail.content.map((curr) => (
...
<Text style={st.subheadingText}>
Title: { curr.title }
Id: { curr.id }
</Text>
...
))}

Categories