I want to add radio button in react native, which is pretty simple and I've done it. But the thing is I want to loop through the radio button upon the contents fetching from a server.So the list depends on the number of items fetching which is changing.The data I'm fetching is as follows
json data
{
"data": [{
"content": "question",
"selection": [
"(a).option1",
"(b).option2 ",
"(c).option3 ",
"(d).option4 "
],
"correct": "4",
}]
}
Well, I'm displaying content inside a CardSection component.I want to loop through the selection array with corresponding radio buttons.I'm using map method for rendering the data. So for selection what should I use?A for loop is okay for that?But I don't know how to do it please do help.Following is the react part.
updated
const formatArray = (arr) => {
let newArr = []
arr.map((item, index) => newArr.push({'label': index, value: item}))
return newArr
}
class QASection extends Component{
render() {
_setActive = (active) => this.setState({this.setState({selected:value})})
return(
{this.state.details.map(a =>
<Card>
<CardSection>
<Text>{a.content}</Text>
</CardSection>
<CardSection>
<RadioForm
radio_props={radio_props}
initial={0}
itemShowKey="label"
itemRealKey="value"
dataSource={formatArray(data)}
onPress={onPress}
/>
<CardSection data={data} key={index} onPress={this._setActive} />
</Card>
)}
);
}
}
By rendering selection[0] it will give me the first value in selection array. But how do I loop through this with radio buttons for each item in an array?
You can loop in the following way
I assume that you are using react-native-radio-form
const formatArray = (arr) => {
let newArr = []
arr.map((item, index) => newArr.push({'label': index, value: item}))
return newArr
}
const YourCardComponent = ({data, onPress}) => {
return (
<Card>
<CardSection>
<Text>{data.content}</Text>
</CardSection>
<CardSection>
<RadioForm
radio_props={radio_props}
itemShowKey="label"
itemRealKey="value"
dataSource={formatArray(data.selection)}
onPress={onPress}
// ... other props as required
/>
</CardSection>
</Card>
)
}
// Inside the class
_setActive = (active) => this.setState({selected:value})
render () {
const {details} = this.state
return (
<View>
{details.map((data, index) => (
<YourCardComponent data={data} key={index} onPress={this._setActive} />
))}
</View>
)
}
Related
Today I tried to delete all the elements that are in my array that I put in a map function, but unfortunately it didn't work.
My code so far -
const inputRefTest = React.useRef([]);
{items[step].mainWord.map((item, index) => {
return (
<Animated.View
key={index}
entering={ZoomIn}
exiting={ZoomOut}
layout={Layout.delay(100)}
onTouchEnd={() => {}}
style={styles.listItem}
>
<SquareGap
id={item}
ref={(el) => (inputRefTest.current[index] = el)}
onPress={() => {}}
/>
</Animated.View>
);
})}
I tried, of course, with
inputRefTest.current = []
but not working. So how can i delete items from ref array? So that when I change the step to add new items via
ref={(el) => (inputRefTest.current[index] = el)}
this line of code. Now when i change the step it has kept the previous items? Why?
I have a component which changes the state when checkbox is checked and the data needs to be updated of the object in the array.
The component state looks something like this
{
key:1,
todo:"Something",
isChecked:false
}
i have 3 files:
AddTodo.js Which passes state & setState to an component TodoList which passes it the subcomponent TodoItem.
I am unable to update the state from TodoItem , I need to implement a function that finds the object from array and updates its isChecked state.
AddTodo.js
function AddTodo() {
const [state, setState] = useState(false);
const [todos, addTodos] = useState([]);
var keys = (todos || []).length;
return (
<View style={styles.container}>
<Modal
animationType="slide"
transparent={true}
visible={state}
statusBarTranslucent={true}
>
<View style={styles.itemsContainer}>
<GetInfoDialog
state={state}
stateChange={setState}
addItem={addTodos}
numKeys={keys}
/>
</View>
</Modal>
{(todos || []).length > 0 ? (
<TodoList data={todos} updateState={addTodos} />
) : null}
<TouchableOpacity
style={styles.btn}
onPress={() => {
setState(true);
}}
>
<Text style={styles.text}>Add New</Text>
</TouchableOpacity>
</View>
);
}
TodoList.js
function TodoList(props) {
return (
<View style={styles.todoList}>
<FlatList
data={props.data}
renderItem={({ item }) => {
console.log(item);
return (
<TodoItem
list={props.data}
itemKey={item.key}
todo={item.todo}
isChecked={item.isChecked}
updateState={props.updateState}
/>
);
}}
backgroundColor={"#000000"}
alignItems={"center"}
justifyContent={"space-between"}
/>
</View>
);
}
TodoItem.js
function TodoItem(props) {
const [checked, setCheck] = useState(props.isChecked);
return (
<View style={styles.todoItem}>
<Checkbox
value={checked}
onValueChange={() => {
setCheck(!checked);
}}
style={styles.checkbox}
/>
<Text style={styles.text}>{props.todo}</Text>
</View>
);
}
renderItem={({ item, index }) => {
console.log(item);
return (
<TodoItem
list={props.data}
itemKey={item.key}
todo={item.todo}
isChecked={item.isChecked}
updateState={props.updateState}
setChecked={(value)=>{
let updatedList = [...yourTodosList]
updatedlist[index].isChecked=value
setTodos(updatedList)
}}
/>
);
}}
and in your todo item
onValueChange={(value) => {
props.setChecked(value);
}}
i also don't think that you need an is checked state in your todo component since you are passing that through props (so delete const [checked, setCheck] = useState(props.isChecked) line and just use the value you are getting from props.isChecked)
didn't pay much attention to your variable names but this should put you on the right track
as per React Native Hooks you have to call
useEffect(() => {
setCheck(checked);
}, [checked]) // now this listens to changes in contact
in TodoItem.tsx
I have this problem - I got multiple checkboxes as a part of my custom component (TimeButtonCheck) rendered on parent screen. On parent screen there is an array which is filled with - whether the checkboxes are checked or unchecked. But there is a problem happening. If I check/uncheck one of those checkboxes, all of them uncheck because they have same state in parent component. When I split the state into these child components I cant modify array of the parent component from child components. Can someone help me to solve this? Here is my code (child element):
const TimeButtonCheck = props => {
const [ceknute, setCeknute] = useState(true);
const [pole, setPole] = useState(["9:00", "10:00", "11:00"]);
const checkHandler = (id) => {
setCeknute(!ceknute);
if(!ceknute) {
const novePole = pole.slice();
novePole.push(id);
console.log("pushuj");
setPole(novePole);
console.log(novePole);
}
else
{
console.log("filtruj");
}
};
return (
<View style={styles.customButon}>
<CheckBox
checked = {ceknute}
key = {props.key}
onPress={(key) => {checkHandler(key)}}
checkedColor = {Colors.primaryColor}
containerStyle = {{padding:0,}}
/>
<TouchableOpacity activeOpacity={0.5}>
<Text
style={styles.textInButton}>
{props.cas}
</Text>
</TouchableOpacity>
</View>
);
And here is my parent component which is mapping those TimeButtonChecks on screen:
const JazdyInstruktor = props => {
const pole = ["8:00", "9:00", "10:00"];
const selectedStartDate = null;
const [isLoading, setIsLoading] = useState(true);
const [displayText, setDisplayText] = useState(true);
const dataToMap = ["11:00", "12:00", "13:00", "14:00", "15:00"];
const maper = (data) => {
return(
<View style = {{marginHorizontal: 18,}}>
<View style ={styles.instruktor}>
<InstruktorBar />
</View>
<View style = {styles.screen}>
{data.map((item) => {
return (
<TimeButtonCheck
key = {item}
cas={item}
/>
)})}
</View>
</View>
);
}
const startDate = selectedStartDate ? selectedStartDate.toString() : '';
const token = useSelector(state => state.auth.token);
return(
<View style={styles.container}>
<CalendarPicker
onDateChange={dateChangeHandler}
/>
<View>
{(isLoading) ? ((displayText) ? (<View style={styles.centered}><Text>Pre zobrazenie volnych terminov si vyberte datum</Text></View>) : (<View style = {{paddingTop: 10,
textAlign: 'center',}}><ActivityIndicator size='large' color={Colors.primaryColor}/></View>)) : **maper(dataToMap)**}
</View>
</View>
This is the case I can not modify parent array called pole through these child components - I can only modify separate arrays for every child component. Is there any way to solve this? Thank you.
Save the state in the parent component, the checkbox component only displays the data.
function CheckBox({ value, label, isChecked }) {
return (
<label>
<input type="checkbox" checked={isChecked} value={value} />
<span>{label}</span>
</label>
);
}
function Parent() {
// list of checkbox, `value` should be the format we want to save, label is something we want to display to the users
const list = [
{ value: "1100", label: "11:00" },
{ value: "1200", label: "12:00" },
{ value: "1300", label: "13:00" }
];
// every item default is un-checked
const [data, setData] = useState(() =>
list.map(item => ({
...item,
isChecked: false
}))
);
// update the check status in the parent component
function handleToggleCheckbox(value) {
setData(list =>
list.map(item => {
if (item.value === value) {
return {
...item,
isChecked: !item.isChecked
};
}
return item;
})
);
}
return (
<div className="App">
{data.map(({ value, label, isChecked }) => (
<CheckBox
key={value}
checked={isChecked}
value={value}
label={label}
onClick={() => handleToggleCheckbox(value)}
/>
))}
</div>
);
}
This is what happens when I console.log(data)
#
so im trying to get the child values from Firebase and then put it on array then show it as a list, but i can't get it to work.
I used ReactNative Elements Lists for showing the list.
Here's my code
const list = [];
export default class ContactPerson extends Component<Props> {
readData() {
firebase.database().ref('contactperson').on('value', function(snapshot) {
snapshot.forEach(function (childSnapshot) {
var data = childSnapshot.val();
list.push(data);
});
});
}
componentDidMount() {
this.readData();
}
renderRow ({ item }) {
return (
<ListItem
roundAvatar
title={item.nama}
subtitle={item.no_hp}
avatar={{uri:item.image_url}}
/>
)
}
render () {
return (
<List>
<FlatList
data={list}
renderItem={this.renderRow}
keyExtractor={item => item.nama}
/>
</List>
)
}}
And then the Firebase Database structure :
Screenshot
You have to pass the item to the method creating single element as following
renderRow (item) {
return (
<ListItem
roundAvatar
title={item.nama}
subtitle={item.no_hp}
avatar={{uri:item.image_url}}
/>
)}
render () {
return (
<List>
<FlatList
data={list}
renderItem={(item) => this.renderRow(item)}
keyExtractor={item => item.nama}
/>
</List>
)
}}
please refer the documentation for flatlist
I have a button that when clicked calls a function that sorts the products by case amount. I am updating the products array so I assumed this would trigger a re-render of the products being mapped in the code below but it is not. Does anyone know how to get this to trigger the products.map to be re-rendered again thus displaying the new sorted products?
render() {
const {products} = this.props;
const cartIcon = (<Icon name="shopping-cart" style={styles.cartIcon} />);
sortCartItems = () => {
products.sort((a, b) => a.cases > b.cases);
}
return (
<View style={styles.itemsInCartContent}>
<View style={styles.cartHeader}>
<TouchableOpacity onPress={sortCartItems}>
{cartIcon}
<Text>Sort</Text>
</TouchableOpacity>
</View>
{products.map((product, index) =>
<CartProductItem
ref="childCartProductItem"
key={product.id}
product={product}
index={index}
activeIndex={this.state.active}
triggerParentUpdate={() => this.collapseAllOtherProducts}
/>
)}
</View>
);
}
A component should not mutate it's own props. If your data changes during the lifetime of a component you need to use state.
Your inline arrow function sortCartItems tries to mutate the products that come from props. Your need to store the products in the components state instead and call setState to change them which will trigger a re-render.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
products: props.products,
}
}
sortCartItems = () => {
this.setState(prevState => ({products: prevState.products.sort((a, b) => a.cases > b.cases);}))
}
render() {...}
}
Note that you need to use a callback in setState whenever you are updating the state based on the previous state. The callback receives the old state as a parameter and returns the new state.
I used a combination of messerbill's and trixn's answers to come up with the following which is now working. And I added a products property to state which receives its data from props.products
render() {
const cartIcon = (<Icon name="shopping-cart" style={styles.cartIcon} />);
sortCartItems = () => {
this.setState({
products: this.state.products.sort((a, b) => a.cases > b.cases)
});
}
return (
<View style={styles.itemsInCartContent}>
<View style={styles.cartHeader}>
<TouchableOpacity onPress={sortCartItems}>
{cartIcon}
<Text>Sort</Text>
</TouchableOpacity>
</View>
{this.state.products.map((product, index) =>
<CartProductItem
ref="childCartProductItem"
key={product.id}
product={product}
index={index}
activeIndex={this.state.active}
triggerParentUpdate={() => this.collapseAllOtherProducts}
/>
)}
</View>
);
}