Why ValueContainer doesn't receive isFocused prop - react-select

I wish to override with custom ValueContainer, there is rendered the component in ValueContainer which style depends on if Select is focused. Why ValueContainer doesn't receive isFocused prop like Placeholder, for example, receives
return (
<SelectContainer
{...commonProps}
className={className}
innerProps={{
id: id,
onKeyDown: this.onKeyDown,
}}
isDisabled={isDisabled}
isFocused={isFocused}
>
{this.renderLiveRegion()}
<Control
{...commonProps}
innerRef={this.getControlRef}
innerProps={{
onMouseDown: this.onControlMouseDown,
onTouchEnd: this.onControlTouchEnd,
}}
isDisabled={isDisabled}
isFocused={isFocused}
menuIsOpen={menuIsOpen}
>
<ValueContainer {...commonProps} isDisabled={isDisabled}>
{this.renderPlaceholderOrValue()}
{this.renderInput()}
</ValueContainer>
In the presented fragment render method of Select from Select.js You can see that isFocused variable is in scope and can be easily passed down.

If you want isFocused to be available in ValueContainer's props, you have to pass it in as one:
<ValueContainer {...commonProps} isDisabled={isDisabled} isFocused={isFocused}>
{this.renderPlaceholderOrValue()}
{this.renderInput()}
</ValueContainer>

Related

Onclick button, state doesn't change

I'm having some troubles understanding the code.
Basically if I do this:
<Text onPress={() => console.log('123')} >123</Text>
,
and I click on the text, it logs me 123 each click.
But I'm doing a dialer app. Basically having a component Tile (representing a single number, also with secondary option (but that will be dealt with later)).
So as I'm including my (currently only single one) Tile in App.js, I want onPress event to call function that changes state of currently dialed number. So if user clicks 3 times on '1', I want the final string to be 111.
The thing is, I can see that the handleNumber() function is called once after running code and never again after clicking on the number, therefore never changing state, not logging anything.
App.js Tile implementation:
const [getNumber, setNumber] = useState();
const handleNumber = (newChar) => {
console.log(newChar);
setNumber(newChar);
}
<Tile onPress={() => handleNumber('1')} style={styles.tile} firstChar={'1'} secondChar={'✉'}/>
Tile.js:
const Tile = (props) => {
return (
<TouchableOpacity onPress={props.onPress()}>
<View>
<Text style={styles.mainChar}>{props.firstChar}</Text>
{props.secondChar ? <Text style={styles.secondChar}>{props.secondChar}</Text> : null}
</View>
</TouchableOpacity>
)
}
One more thing:
As you can see in App.js::handleNumber(),
the implementation is currently wrong, because the final number will always be just the new single number, instead of appending it to the end of string.
But if I wanted to do smth like setNumber(getNumber + newChar), it would give Maximum update depth exceeded error.
The thing here is the way that you're passing the onPress prop to TouchableOpacity. See, you're calling the props.onPress function instead of just passing it to the component, which causes the function to be executed when the component renders (or rerenders).
You should be fine just by using <TouchableOpacity onPress={props.onPress}> and then setNumber(getNumber + newChar) will be fine as well.
As a side note, you could initialize your App.js state with the '1' string that you wish to be your initial value (const [getNumber, setNumber] = useState('1')), and then the Tile component can receive getNumber directly.

Passing Params in The Same Screen. React Native

I know how to pass parameters to other screen. For example:
<Flatlist
data={SOMEDATA}
renderItem={(itemData) => (
<Button
onPress={() => {
props.navigation.navigate("myScreen", {
myId: itemData.item.id,
})
}}
>
</Button>
/>
Then I can access myId on the myScreen screen by props.route.params.myId, But I don't know how to access it in the same screen I am using (same js file). if I write props.route.params.myId, I will get this error :
undifined is not an object (evaluating 'props.route.params.myId'
any help please?
are you trying to set a property in the state of your current screen?
if so, what you need is a state
assuming you are using a functional react component and not a class based component, what you need to do is to introduce a state to your component
const [state, setState] = useState(initialState);
when ever you want to change your state, you just need to call the setState(myNewObj) function,
whenever you want to access your state
you can just call for state
the initiateState can be anything
in your case something like
const [myId, setMyId] = useState(-1);
I suggest you take alook at the official React Documentation
https://reactjs.org/docs/hooks-reference.html#basic-hooks

How to update attribute value by using ref in react native?

In below code there is "opened" attribute and I want to change its value by using ref. Here I am using ref as indexed array.
<Menu renderer={renderers.SlideInMenu} ref={(Menu) => { this.rowRefs[item.id] = Menu; }} opened={false}>
I tried it as
function updateRef(id){
React.findDOMNode(this.refs.id).setAttribute("opened", true);
}
Can anyone please explain how to create an indexed reference and how to use it?
Props should be immutable and for the purpose of dynamically change update them you should consider to set them via state.
Your code should look like:
<Menu renderer={renderers.SlideInMenu} ref={component => this.menuRef = component }} opened={this.state.opened}>
In which case the <Menu .. > is assumed to be rendered in a component which has a state variable opened which you can change using this.setState({opened: true}) . This state change will make your UI rerender hence <Menu .. > will be rendered with opened={true}.
Also if you want to use ref, then you should consider making a state variable inside Menu which should be initialized with opened prop, and you should have a method in the Menu which will change the state.
Your code should look like below:
class Menu extends React.Component {
constructor (props) {
super(props);
this.state = {
menuOpened: props.opened
}
}
changeMenuOpened = (value) => {
this.setState({
menuOpened: value
})
}
.....
}
and then you can just call the changeMenuOpened method using Menu's ref from the parent.
this.menuRef.changeMenuOpened(true);

React Native Material Dropdown - How to Handling onPress event dropdown?

I have an app that needed to access different API, depending on which dropdown user touch,
so far I'm calling an API in componentWillMount() to create a Label and item Value on dropdown itself :
api.get('MyURL')
.then((response)=> {
var jsonResult = JSON.parse(response.data)
var result = jsonResult.reduce((r,o)=> r.concat(...Object.values(o)),[])
console.log(result)
this.setState({data: result})
})
.catch((err)=>{
console.log("axios cathing error")
Alert.alert("failed", "Retry to retrieve from API", [{text:'OK', onPress:()=>{this.componentWillMount()}}])
console.log(err)
})
// Rendering Dropdown
<Dropdown
ref={(ref) => this.dropdown = ref}
onFocus={()=>{console.log("onFocus"), console.log(index)}}
dropdownOffset={{top:10, left:30}}
dropdownPosition={0}
itemCount={4}
containerStyle={{borderWidth:1, borderColor:'lightgrey', borderRadius:50, width:DeviceWidth*0.8, paddingLeft:DeviceWidth*0.02}}
inputContainerStyle={{ borderBottomColor: 'transparent' }}
data={data}
itemTextStyle={global.global.TextBold}
valueExtractor={({value})=> value}
onChangeText={(value)=>{this.onChangeTextPress(item.name, value, index)}}
value={this.state.selected[item.name]}
/>
but I dont see any props to handling onPress, just onChangeText props declared on readme
and there's onFocus props that doesn't declared in readme to handling touch, but onFocus just work in case there's some item in dropdown,
there's someway to handling touch that work even there's no item in dropdown?
From the react-native-material-dropdown source, onPress returns if itemCount is 0.
So the only solution is to fork the repo and move the onFocus call to above the !itemCount check (or add in a different props method to retain the current API behavior), then publish and use your own fork (or just move the module into your own project source).
Alternatively, change your design to use [{ value: 'Loading...' }] as the initial data, which might be better UX.

React Native FlatList Not Re-Rendering after Asyncronous operation

I have an async function like this:
getDeals() {
if(this.props.user) {
this.setState({loading: true});
this.setState({deals: []});
var parameters = {
zip: this.props.user.zip,
sort: 'All',
category: this.props.selectedCategory,
company: this.props.user.company,
page: null,
user: this.props.user,
search: null
}
axios.post(`${constants.api}/grab-deals/`, parameters)
.then((response) => {
this.setState({totalDeals: response.data.length});
this.setState({deals: response.data, loading: false, refreshing: false});
this.forceUpdate();
})
}
}
And a FlatList component Like this:
<FlatList data={this.state.deals} style={{flex: 1, padding: 10}} extraData={this.state} keyExtractor={this.keyExtractor} renderItem={this.renderDeal.bind(this)} />
Here is the keyextractor:
keyExtractor = (item, index) => item.id;
When I call this.getDeals() the first time it works great. However when I call it a second time the axios call get's all of the correct data, but the flat list still keeps old data (it doesn't remove items that aren't in the new call).
How do I get the FlatList to always reflect the returned data?
Call this.getDeals() in componentWillUpdate() and update props?
I believe you confussing what props and state is for. Basically state is used for things that could change during the lifecycle of the component and props are kept immutable. I use them for behavior.
Unless you are changing the parameters for the getDeals function on the second call, see that all of the properties are based on the props, which are not always updated.
RN has a method called componentWillUpdate that is triggered with the new props which you can then be used to update the component itself. If you want to keep using props in your getDeals method, you will need to check if the props have changed (this happens when the parent updates the child with new props) and then trigger again the data fetch.
If this does not help, please post more code.
According to the docs you need to set the state.selected value
By passing extraData={this.state} to FlatList we make sure FlatList
itself will re-render when the state.selected changes. Without setting
this prop, FlatList would not know it needs to re-render any items
because it is also a PureComponent and the prop comparison will not
show any changes.