React Native multiple switches - javascript

On React-Native, I'm trying to create a screen with multiple switch components, with the possibility of selecting only one at once. When the component loads, only the first switch in on. if you click on it, it turns to off, but if you turn on another one, all the others turn to off.
I'm not sure I have the right approach here, as I'm confused about how to use the component state to do this.
In JS, I would do something like a function that turns all switch to off, but turn on the clicked one, but I don't understand how to this with state.
thanks in advance
import React from 'react'
import { ScrollView, Text, View, Switch } from 'react-native'
class switchScreen extends React.Component {
constructor (props) {
super(props)
this.state = {
trueSwitchIsOn: true,
falseSwitchIsOn: false
}
}
switch = (value) => {
this.setState({ falseSwitchIsOn: value, trueSwitchIsOn: !value })
}
render () {
return (
<View>
<Switch
onValueChange={this.switch}
value={this.state.trueSwitchIsOn}
/>
<Switch
onValueChange={this.switch}
value={this.state.falseSwitchIsOn}
/>
<Switch
onValueChange={this.switch}
value={this.state.falseSwitchIsOn}
/>
</View>
)
}
}

I believe a more optimal solution would minimize the amount of state, and possibility of inconsistent data. Using one state variable to keep track of which switch is active (if any) can solve your problem pretty easily.
import React from 'react'
import { ScrollView, Text, View, Switch } from 'react-native'
class switchScreen extends React.Component {
constructor (props) {
super(props)
this.state = {
activeSwitch: null,
}
}
// A simple toggle method that takes a switch number
// And toggles it between on / off
toggleSwitch = (switchNumber) => {
this.setState({
activeSwitch: switchNumber === this.state.activeSwitch ? null : switchNumber
})
};
//
switchOne = (value) => { this.toggleSwitch(1) };
switchTwo = (value) => { this.toggleSwitch(2) };
switchThree = (value) => { this.toggleSwitch(3) };
render () {
return (
<View>
<Switch
onValueChange={this.switchOne}
value={this.state.activeSwitch === 1}
/>
<Switch
onValueChange={this.switchTwo}
value={this.state.activeSwitch === 2}
/>
<Switch
onValueChange={this.switchThree}
value={this.state.activeSwitch === 3}
/>
</View>
)
}
}

import React from 'react'
import { ScrollView, Text, View, Switch } from 'react-native'
class switchScreen extends React.Component {
constructor (props) {
super(props)
this.state = {
switchone:false,
switchtwo:false,
switchthree:false,
}
}
switchOne = (value) => {
this.setState({ switchone: !value,
switchtwo:false,switchthree:false,
})
}
switchTwo = (value) => {
this.setState({ switchtwo: !value,
switchone:false,switchthree:false,
})
}
switchThree = (value) => {
this.setState({ switchtree: !value,
switchone:false,switchtwo:false,
})
}
render () {
return (
<View>
<Switch
onValueChange={this.switchOne}
value={this.state.switchone}
/>
<Switch
onValueChange={this.switchTwo}
value={this.state.switchtwo}
/>
<Switch
onValueChange={this.switchThree}
value={this.state.switchthree}
/>
</View>
)
}
}

You can try something like below, you can keep array of switch states, in the example its an associative key, but you can change according to your need, with multi level switch states. (pardon the code formatting but it give you the idea)
constructor(props) {
super(props);
this.state = {
switchStates: {
companyName: true
}
}
}
toggle(item, index) {
const switchStates = this.state.switchStates;
switchStates[index] = !switchStates[index];
console.log(switchStates);
this.setState({ switchStates });}
render switch
<Switch
onValueChange={isSwitchOn =>
this.toggle({ isSwitchOn }, "companyName")
}
value={this.state.switchStates.companyName}
/>

Related

How to implement multiselect using Flatlist in react native?

I am trying to create a flatlist with text,but it selects only single value but i want to select multiple values from the list. and i also need color change for selected item. Here i am fetching data from api.
Here is my code:
import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { FlatList } from "react-native";
import {
stepDone,
setInputData,
} from "../../actions";
import Options from "../../components/Options";<----- It is a component Here define the flatlist
class Qualifier extends React.Component {
_afterQualifierSelected = (id, name) => {
const { stepDone, setInputData, input, updateSymptom } = this.props,
symptomId = input.symptomIds[input.symptomIds.length - 1],
currentSymptom = input.symptoms.filter(entry => entry.id === symptomId),
symptom = currentSymptom ? currentSymptom[0] : {};
symptom.qualifier = id;
setInputData("qualifier", { id, name });
stepDone("qualifierSelected");
};
render = () => {
return (
<Options
data={this.qualifiers}
exclusive={true}
onSelect={this._afterQualifierSelected}
/>
)
}
}
options.js
export default class Options extends React.PureComponent {
static propTypes = {
data: PropTypes.array.isRequired,
extraData: PropTypes.object,
exclusive: PropTypes.bool.isRequired,
onSelect: PropTypes.func.isRequired,
onDone: PropTypes.func
};
_keyExtractor = (item, index) =>
"undefined" === typeof item.id
? index.toString()
: "string" === typeof item.id
? item.id
: item.id.toString();
_renderItem = ({ item }) => {
const { onSelect } = this.props;
return <Item id={item.id} text={item.name} onPress={onSelect} />;
};
render = () => {
const { data, extraData, exclusive, onDone } = this.props;
return (
<View style={styles.container}>
<View style={styles.listContainer}>
<FlatList
data={data}
extraData={extraData}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
</View>
{!exclusive && (
<Button
style={styles.done}
onPress={onDone}
title={Language.done}
accessibilityLabel={Language.optionsDoneAccessibility}
/>
)}
</View>
);
};
}
How should i implement multi select in this flat list using react native?
Can somebody help me to solve this issue?
Check out the multi-select-flatlist example from the official docs. The ListItems are components with their own state & props. You can pass them down whenever your List-component receives a click and do some magic with conditional rendering.

React Native: Component rerender but props has not changed

I'm encountering this strange issue that I can figure out why is happing.
This should not be happening since the prop passed down to the History component has not been updated.
./components/History.js
...
const History = ({ previousLevels }) => {
return (
<ScrollView style={styles.container}>
{previousLevels.reverse().map(({ date, stressValue, tirednessValue }) => {
return (
<CardKBT
key={date}
date={date}
stressValue={stressValue}
tirednessValue={tirednessValue}
/>
)
})}
</ScrollView>
)
}
...
export default History
As can be seen in this code (below), the prop to the History is only updated once the user press Save.
App.js
import React from 'react'
import { View, ScrollView, StyleSheet } from 'react-native'
import { AppLoading, Font } from 'expo'
import Store from 'react-native-simple-store'
import { debounce } from 'lodash'
import CurrentLevels from './components/CurrentLevels'
import History from './components/History'
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
isLoadingComplete: false,
currentLevels: {
stressValue: 1,
tirednessValue: 1,
},
previousLevels: [],
}
this.debounceUpdateStressValue = debounce(this.onChangeStressValue, 50)
this.debounceUpdateTirednessValue = debounce(
this.onChangeTirednessValue,
50
)
}
async componentDidMount() {
const previousLevels = await Store.get('previousLevels')
if (previousLevels) {
this.setState({ previousLevels })
}
}
render() {
const { stressValue, tirednessValue } = this.state.currentLevels
if (!this.state.isLoadingComplete && !this.props.skipLoadingScreen) {
return (
<AppLoading
...
/>
)
} else {
return (
<View style={{ flex: 1 }}>
<CurrentLevels
stressValue={stressValue}
onChangeStressValue={this.debounceUpdateStressValue}
tirednessValue={tirednessValue}
onChangeTirednessValue={this.debounceUpdateTirednessValue}
onSave={this.onSave}
/>
<History previousLevels={this.state.previousLevels} />
</View>
)
}
}
...
onChangeStressValue = stressValue => {
const { tirednessValue } = this.state.currentLevels
this.setState({ currentLevels: { stressValue, tirednessValue } })
}
onChangeTirednessValue = tirednessValue => {
const { stressValue } = this.state.currentLevels
this.setState({ currentLevels: { stressValue, tirednessValue } })
}
onSave = () => {
Store.push('previousLevels', {
date: `${new Date()}`,
...this.state.currentLevels,
}).then(() => {
Store.get('previousLevels').then(previousLevels => {
this.setState({
currentLevels: { stressValue: 1, tirednessValue: 1 },
previousLevels,
})
})
})
}
}
The component will re-render when one of the props or state changes, try using PureComponent or implement shouldComponentUpdate() and handle decide when to re-render.
Keep in mind, PureComponent does shallow object comparison, which means, if your props have nested object structure. It won't work as expected. So your component will re-render if the nested property changes.
In that case, you can have a normal Component and implement the shouldComponentUpdate() where you can tell React to re-render based on comparing the nested properties changes.

How to implement search logic in javascript/react native/redux

I want to implement search logic that will be in some method, and then I would pass it to the TextInput props 'onChangeText'. I guess that I should iterate through array 'popularMovies' and find if my input value match the specific title. The problem is that I am not sure how that should look.
Thank you in advance!
import React, { Component } from 'react';
import { FlatList, View, StatusBar, TextInput } from 'react-native';
import { bindActionCreators } from 'redux';
import type { Dispatch as ReduxDispatch } from 'redux';
import { connect } from 'react-redux';
import { fetchPopularMovies } from '../../actions/PopularMovieActions';
import addToFavourite from '../../actions/FavouriteMovieActions';
import MovieCard from '../../components/movieCard/MovieCard';
type Props = {
fetchPopularMovies: Function,
popularMovies: Object,
navigation: Object,
}
class ListOfPopularContainer extends Component<Props> {
state = {
refreshing: false,
text: '',
}
componentDidMount() {
this.props.fetchPopularMovies();
}
search(text) {
this.setState({ text });
// SEARCH LOGIC SHOULD GO HERE
}
onRefresh() {
this.setState({ refreshing: true });
this.props.fetchPopularMovies();
this.setState({ refreshing: false });
}
render() {
const { popularMovies, navigation } = this.props;
return (
<View>
<TextInput
placeholder="Search movie"
onChangeText={ (text) => this.search(text) }
value={this.state.text}
/>
<StatusBar
translucent
backgroundColor="transparent"
barStyle="light-content"
/>
<FlatList
onRefresh={() => this.onRefresh()}
refreshing={this.state.refreshing}
data={popularMovies}
keyExtractor={item => item.title}
renderItem={({ item }) => (
<MovieCard
addToFavourite={() => this.props.addToFavourite(item)}
navigation={navigation}
card={item}
/>
)}
/>
</View>
);
}
}
const mapStateToProps = state => ({
popularMovies: state.popularMovies.popularMovies,
});
const mapDispatchToProps = (dispatch: ReduxDispatch): Function => (
bindActionCreators({ fetchPopularMovies, addToFavourite }, dispatch)
);
export default connect(mapStateToProps, mapDispatchToProps)(ListOfPopularContainer);
I'm unsure what you're asking, your setup is correct and this looks good. Do you want to know how to filter through your popular movies? This would be one way of implementing it with vanilla JS.
search(text) {
this.setState({ text });
// SEARCH LOGIC SHOULD GO HERE
let searchedMovies = this.state.popularMovies.filter(ele =>
ele.title.includes(text))
this.setState({searchedMovies})
}
you should check out lodash. two functions in particular:
Includes
https://lodash.com/docs/4.17.10#includes
this function checks if one string is included in another string.
import { includes } from 'lodash';
search(text) {
var searchResults = [];
var { popularMovies } = this.props;
for (var i = popularMovies.length -1; i >= 0; i--) {
includes(popularMovies[i], text) && searchResults.push(popularMovies[i])
}
return searchResults;
}
debounce
https://lodash.com/docs/4.17.10#debounce
this function throttles a function so as the user is typing it will regularly search at the phrase at reasonable intervals
debounce(search(text))

Clear input in stateless React component

I want to implement an X icon inside Input component that will clear the input field. I can easily do it if I control the state. But is it actually possible with stateless component?
I use react-semantic-ui, their stateful components have auto controlled state.
So I want to create an input that can be used like this:
//Controlled
class App extends React.Component {
state = {
value:''
}
onChange = (event, props) => {
this.setState({value: props.value});
}
onClearInput = () => {
this.setState({value: ''});
}
render() {
return (
<MyInput
clearable
value={this.state.value}
onChange={this.onChange}
onClearInput={this.onClearInput}
/>
)
}
}
Or
// Uncontrolled
class App extends React.Component {
onChange = (event, props) => {
doSomething(props.value);
}
render() {
return (
<MyInput
clearable
onChange={this.onChange}
/>
)
}
}
In the second example, clearable feature will not work because we're not controlling the value.
MyInput can be implemented like this:
import React from 'react';
import { Input } from 'semantic-ui-react';
import ClearIcon from './ClearIcon';
function MyInput(props) {
const prepareProps = {...props};
if (props.clearable) {
prepareProps.icon=<ClearIcon onClick={props.onClearInput} />;
delete prepareProps.clearable;
}
delete prepareProps.onClearInput;
return (
<div className="my-input">
<Input {...prepareProps} />
</div>
);
}
...etc.
My problems:
clearable feature must work in both controlled and uncontrolled manner.
clearable feature should not require a handler. It would be nice to just provide a prop and handle the render and behavior of the X button under the hood.
I don't see any way to make this work. Any ideas?
Allowing the user of your component to set the value via props and still being able to clear the input can be easily achieved, e.g. like this:
class MyInput extends React.Component {
constructor(props) {
super(props);
this.state = {value: props.value || ''};
}
handleChange = event => {
const { onChange } = this.props;
this.setState({ value: event.currentTarget.value });
onChange && onChange(event);
};
handleClear = () => {
const { onClearInput } = this.props;
this.setState({ value: "" });
onClearInput && onClearInput();
};
render() {
const { value } = this.state;
const { clearable, onChange, ...inputProps } = this.props;
const clearIcon = clearable && <ClearIcon onClick={this.handleClear} />;
return (
<div className="my-input">
<Input value={value} icon={clearIcon} onChange={this.handleChange} {...inputProps} />
</div>
);
}
}
You could even make it more composable by using an hoc or render props as proposed by #pkuzhel.
Look at this codesandbox example to see it in action.
#Andrey
Would you try this below code? and let me know if that resolves your issue.
import React, { Component } from 'react';
import { Input, Button } from 'semantic-ui-react'
class App extends Component {
clear = () => {
console.log(this.inputRef.target.value);
this.inputRef.target.value = '';
}
render() {
return (
<div className="App">
<Input placeholder='Search...' onChange={(input) => {input.persist(); this.inputRef = input}} />
<Button onClick={this.clear}>Clear</Button>
</div>
);
}
}

React.JS - multiple elements sharing a state ( How do I modify only one of the elements without affecting the others? )

class App extends Component {
constructor(props) {
super(props);
this.state = { Card: Card }
}
HandleEvent = (props) => {
this.SetState({Card: Card.Active}
}
render() {
return (
<Card Card = { this.state.Card } HandleEvent={
this.handleEvent }/>
<Card Card = { this.state.Card } HandleEvent={
this.handleEvent }/>
)
}
}
const Card = props => {
return (
<div style={props.state.Card} onClick={
props.HandleEvent}>Example</div>
)
}
Every time I click on one of the cards all of my elements change states, how do I program this to only change card that I clicked?
Here's a working example
import React, { Component } from 'react'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
0: false,
1: false
};
}
handleEvent(idx) {
const val = !this.state[idx];
this.setState({[idx]: val});
}
render() {
return (
<div>
<Card state={this.state[0]} handleEvent={()=>this.handleEvent(0) } />
<Card state={this.state[1]} handleEvent={()=>this.handleEvent(1) } />
</div>
);
}
}
const Card = (props) => {
return (<div onClick={() => props.handleEvent()}>state: {props.state.toString()}</div>);
}
You can also see it in action here
Obviously this is a contrived example, based on your code, in real world application you wouldn't store hardcoded state like {1: true, 2: false}, but it shows the concept
It's not completely clear from the example what is the Card in the constructor. But here the example of how you can modify clicked element.
Basically you can keep only index of clicked element in parent's state, and then pass it as some property to child component, i.e. isActive here:
const cards = [...arrayOfCards];
class App extends Component {
constructor(props) {
super(props);
this.state = { activeCardIndex: undefined }
}
HandleEvent = (index) => {
this.SetState({
activeCardIndex: index
});
}
render() {
return ({
// cards must be iterable
cards.map((card, index) => {
return (
<Card
key={index}
Card={Card}
isActive={i === this.state.activeCardIndex}
HandleEvent={this.HandleEvent.bind(this, index)}
/>
);
})
});
}
}
const Card = props => {
// style active card
const style = Object.assign({}, props.Card, {
backgroundColor: props.isActive ? 'orange' : 'white',
});
return (
<div style={style} onClick={
props.HandleEvent}>Example</div>
)
}

Categories

Resources