I was trying to modify my custom header according to one parameter that is in the state from the same component. But I see that it does not work. I can do the same inside the render and it obviously does but how can I do it in the header?
In this case for instance, I would like to change the button for another if itemNumber > 0
...
static navigationOptions = ({ navigation }) => {
return{
title: "Edit Group"+' ',
headerStyle: {
backgroundColor: '#2ca089',
elevation: 0,
shadowOpacity: 0,
borderBottomWidth: 0,
},
headerTintColor: '#fff',
headerRight: (
<Button hasText transparent onPress={() =>
Alert.alert(
"Delete Group",
"Are you sure you want to delete this group? It is a non-reversible action!",
[
{text: 'Yes', onPress: () => console.log('Yes Pressed')},
{text: 'No', onPress: () => console.log('No Pressed'), style: 'cancel'},
],
)
}>
<Text>Delete Group</Text>
</Button>
),
};
}
constructor(props) {
super(props)
this.state = {
dataSource : [],
text : '',
itemNumber : 0,
}
}
...
I understand that because it is a static component it will not be modified dynamically but I do not see how can I do it in another fashion.
Thanks,
I can not see where the answer from TNC implement the callback function inside the headerRight in order to re-update the navigation header which I think it is the problem.
My solution is the following:
The variable which you want to observe is itemNumber, make sure is in the constructor ✅
constructor(props) {
super(props)
this.state = {
dataSource : [],
text : '',
itemNumber : 0,
selectedItems: []
}
}
Then, inside the function which you trigger the event which requires the update for the header add the following code:
triggerFunction = parameters => {
//...
let newValue = 1 //Implement your logic
this.setState(({itemNumber}) => {
this.props.navigation.setParams({itemNumber: newValue})
return {itemNumber: newValue }
});
//...
};
To conclude, on the navigationOption add the following code:
static navigationOptions = ({ navigation }) => {
return{
headerRight:
navigation.getParam('itemNumber', 0) > 0
?
<Button hasText transparent onPress={() =>
Alert.alert(
"Delete User",
"Are you sure you want to delete this user/users? It is a non-reversible action!",
[
{text: 'Yes', onPress: () => console.log('Yes Pressed')},
{text: 'No', onPress: () => console.log('No Pressed'), style: 'cancel'},
],
)
}>
<Text>Delete Users</Text>
</Button>
:
null
};
}
I have got the inspiration from this answer:
https://stackoverflow.com/a/51911736/5288983
I also attach you the documentation where you can understand better the approach:
https://reactnavigation.org/docs/en/headers.html#setting-the-header-title
You can pass multiple params to navigator as:
From Calling Container/Component
this.props.navigation.navigate('navigator-destination', {
title: 'Your Title',
label: 'Extra Params',
callback: callback // Even callback
});
In Called Container/Component
static navigationOptions = ({navigation}) => {
const {state} = navigation;
label = state.params.label;
return {
title: `${state.params.title}`,
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
};
};
To call callback:
_someMethod = () => {
const {navigation} = this.props;
navigation.state.params.callback(parameters);
navigation.goBack();
};
Related
Building an internal company app, I need to ask a question before the app renders to determine fields.
I have this code.
useEffect(() => {
if (startup) {
console.log('Display Alert');
{
createTwoButtonAlert;
}
}
}, []);
For my useEffect, then here is my alert
const createTwoButtonAlert = () =>
Alert.alert('Title', 'Here is my Question?', [
{
text: 'Yes',
onPress: () => {
setQuestion(false), setStartup(false);
},
},
{
text: 'No',
onPress: () => {
setQuestion(true), setStartup(false);
},
},
]);
This alert is not displaying on startup with the current code.
Try putting the alert code directly inside useEffect inside the root (App) component. It will run only once when the component mounts.
useEffect(() => {
Alert.alert('Title', 'Here is my Question?', [{
text: 'Yes',
onPress: () => {
setQuestion(false), setStartup(false);
},
},
{
text: 'No',
onPress: () => {
setQuestion(true), setStartup(false);
},
},
]);
}, [])
Ok, while Grabriel's response did work. This was one of those stupid mistakes.
I forgot to inclose my alert in {}
a simple fix.
const createTwoButtonAlert = () => {
Alert.alert('Title', 'Here is my Question?', [
{
text: 'Yes',
onPress: () => {
setQuestion(false), setStartup(false);
},
},
{
text: 'No',
onPress: () => {
setQuestion(true), setStartup(false);
},
},
]);
}
I am at a very primitive stage of learning react-native. And I am trying to solve a simple problem, which may sound silly, but I really want to know the answer.
I have a json file
data.js
export const PRODUCT_DATA = [
{
name: 'abc',
price: 90,
weight: '1 kg',
currency: 'INR',
liked: true,
image: require('../assets/images/carrots/Rectangle238.png')
},
{
name: 'bce',
price: 10,
weight: '1 kg',
currency: 'USD',
liked: false,
image: require('../assets/images/mango/Rectangle234.png')
},
{
AllCategoriesComponent: [
{
icon: "home-outline",
name: "Household",
shape: true,
},
{
icon: "basket-outline",
name: "Grocery",
shape: false,
},
{
icon: "ios-podium",
name: "Milk",
shape: true,
},
{
icon: "ios-rose",
name: "chilled",
shape: false,
},
{
icon: "hardware-chip",
name: "Drinks",
shape: true,
},
{
icon: "cloud",
name: "Pharmacy",
shape: true,
},
{
icon: "fast-food",
name: "Frozen Food",
shape: true,
},
{
icon: "football",
name: "Vegetable",
shape: true,
},
{
icon: "bulb",
name: "Meat",
shape: true,
},
{
icon: "football",
name: "Vegetable",
shape: true,
},
{
icon: "bulb",
name: "Meat",
shape: true,
},
]
},
];
ANd below is screen file
screen.js
import { SearchBar } from 'react-native-elements';
import { Text, View, TextInput } from 'react-native';
import React from 'react';
import { PRODUCT_DATA } from "./data";
export default class App extends React.Component {
constructor() {
super();
this.state = {
search: '',
}
}
updateSearch = (search) => {
this.setState({ search: search });
};
render() {
const { search } = this.state;
return (
<View>
<SearchBar onChangeText={this.updateSearch} value={search} />
{PRODUCT_DATA[2].AllCategoriesComponent.map((item, index) => {
if (item.name === this.state.search) {
return (
<View style={{ backgroundColor: "white" }}>
<Text>{search}</Text>
</View>
);
} else {
return (<Text></Text>);
}
})}
<Text>{this.state.search}</Text>
</View>
);
}
}
As you can see this is not a good solution. I am able to print the output only if I type full name in the SearchBar. Also it seems all the item.name are already on the screen, which comes up when value of search bar matches it. I want to start showing the output as soon as something is typed on the SearchBar
This might help please look into it
import { FlatList, Text, View, TextInput } from "react-native";
export default class Example extends Component {
constructor(props) {
super(props);
this.state = {
text: "",
data: [],
};
this.arrayholder = [];
}
componentDidMount() {
const data = PRODUCT_DATA[2].AllCategoriesComponent.map((item, index) => {
return item;
});
this.setState({ data }, () => {
this.arrayholder = data;
});
}
searchData(text) {
const newData = this.arrayholder.filter((item) => {
const itemData = item.name.toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
data: newData,
text: text,
});
}
render() {
return (
<View style={styles.MainContainer}>
<TextInput
onChangeText={(text) => this.searchData(text)}
value={this.state.text}
placeholder="Search Here"
/>
<FlatList
data={this.state.data}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => <Text style={styles.row}>{item.name}</Text>}
/>
</View>
);
}
}
I've been going through HighStock API to try and find which config and options I need to pass to the ChartView component in react-native-highcharts to draw my graph. I'm having a hard time finding what combination of config and options will get my desired result, things like series, dataGrouping, etc... . My data is a 2 dimensional array with 4 values for OHLC. My desired result is the photo at the top of this stackoverflow.
Here is my code so far.
class OHLC extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: "OHLC",
headerLeft: (
<TouchableOpacity
style={NavStyles.headerButton}
onPress={() => navigation.openDrawer()}>
<Icon name="bars" size={20} />
</TouchableOpacity>
),
})
render() {
var Highcharts='Highcharts';
var conf={
title: {
text: 'Stock Name'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Price'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
// tooltip: {
// formatter: function () {
// return '<b>' + this.series.name + '</b><br/>' +
// Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
// Highcharts.numberFormat(this.y, 2);
// }
// },
legend: {
enabled: false
},
// exporting: {
// enabled: false
// },
series: [{
type: 'ohlc',
name: 'AAPL Stock Price',
data: (function () {
let arrays = aExtractFromJson(data,'data', null,null);
arrays = ohlcExtractor(arrays);
return arrays;
// look at toFixed method for number to limit decimal point
}()),
dataGrouping: {
units: [[
'week', // unit name
[1] // allowed multiples
], [
'month',
[1, 2, 3, 4, 6]
]]
}
}]
};
const options = {
global: {
useUTC: false
},
lang: {
decimalPoint: ',',
thousandsSep: '.'
}
};
return (
<View>
<ChartView style={{height:300}} config={conf} options={options} stock={true} ></ChartView>
//To see if anything gets rendered.
<Text>HELLO DAVID!</Text>
</View>
);
}
}
After further research, I was able to find the config and options needed to create an OHLC Graph using the ChartView component in react-native-highcharts. I encountered some issues with rendering a blank screen so I added javaScriptEnabled={true} domStorageEnabled={true} originWhitelist={['']} to my ChartView.
In the config the essentials:
series with type: 'ohlc' and data: [[1,2,3,4],[2,3,4,5]] inside.
In options, no arguments are required, I left it as options='' in the ChartView.
Don't forget to add stock={true} in ChartView
My code, basic example:
import React, {Component} from 'react';
import {View} from 'react-native';
import ChartView from 'react-native-highcharts';
class OHLC extends React.Component {
constructor(props) {
super(props);
}
render() {
var Highcharts='Highcharts';
var conf={
chart: {
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
type: 'ohlc',
name: 'Random data',
/*Open, high,low,close values in a two dimensional array(two days)*/
data: [[1,2,3,4],[2,3,4,5]],
}]
};
return (
<View style={{borderRadius: 4, marginTop: 30,}}>
<ChartView style={{height:500}} config={conf} javaScriptEnabled={true} domStorageEnabled={true} originWhitelist={['']} stock={true} options=''></ChartView>
</View>
);
}
}
I need to display an icon before the selected value using react-select and typescript.
This is what I tried so far:
SingleValue: React.SFC<SingleValueProps<OptionType>> = ({ children, ...props }) => (
<components.SingleValue {...props}>
<i className={`fal fa-${this.props.icon} has-text-grey-light`} /> {children}
</components.SingleValue>
)
The main issue is with type definitions that expects that children passed to components.SingleValue must be a string.
You don´t have to use the standard components. You can easlily create a custom one but still keep the styles it needs.
The only requirement you need is emotion to get the styles the SingleValue component uses.
/**
* This Example uses the `FontAwesome` React library.
**/
const options = [
{ label: "Value A", value: "a", icon: faCoffee },
{ label: "Value B", value: "b", icon: faCar },
{ label: "Value C", value: "c", icon: faMobile },
{ label: "Value D", value: "d", icon: faCircle },
{ label: "Value E", value: "e", icon: faSquare }
];
const SingleValue = ({
cx,
getStyles,
selectProps,
data,
isDisabled,
className,
...props
}) => {
console.log(props);
return (
<div
className={cx(
emotionCss(getStyles("singleValue", props)),
{
"single-value": true,
"single-value--is-disabled": isDisabled
},
className
)}
>
<FontAwesomeIcon icon={data.icon} style={{ marginRight: 10 }} />
<div>{selectProps.getOptionLabel(data)}</div>
</div>
);
};
export default class MySelect extends Component {
render() {
return (
<Select
options={options}
components={{ SingleValue }}
styles={{
singleValue: (provided, state) => ({
...provided,
display: "flex", // To keep icon and label aligned
alignItems: "center"
})
}}
/>
);
}
}
Working example
My code:
const tabscreen = (screen, path, label, src) => {
return {
screen, path,
navigationOptions: {
tabBarLabel: label,
tabBarIcon: ({
tintColor,
focused = true
}) => (<TabIcon src={src} active={focused}/>),
}
};
};
const MainTab = TabNavigator({
Home: tabscreen(HomeScreen, '/home', 'home', 'home'),
Chat: tabscreen(ChatScreen, '/chat', 'chat', 'chat'),
Find: tabscreen(FindScreen, '/find', 'find', 'find'),
Profile: tabscreen(ProfileScreen, '/profile', 'find', 'profile')
}, {
tabBarPosition: 'bottom',
swipeEnabled: false,
animationEnabled: false,
lazy: false,
//...other configs
tabBarOptions: {
// tint color is passed to text and icons (if enabled) on the tab bar
activeTintColor: '#1BBC9B',
inactiveTintColor: '#9B9B9B',
showIcon: true,
style: {
backgroundColor: '#F4F4F4',
borderTopWidth: 0,
height: 49
},
labelStyle: {
marginTop: 0,
marginLeft: 0,
marginRight: 0,
marginBottom: 1.5
}
}
});
const AppNavigator = StackNavigator({
Main: {
screen: MainTab ,
path: '/',
navigationOptions: {
header: null,
headerVisible: false,
gesturesEnabled: false,
}
},
}, {
initialRouteName: 'Main',
mode: 'card',
headerMode: 'screen',
navigationOptions: {
headerVisible: false,
gesturesEnabled: true,
headerStyle: styles.headerStyle,
headerTitleStyle: styles.headerTitleStyle,
headerTintColor: 'white',
headerBackTitle: null,
}
});
This demo uses redux to control state.
In the FindScreen, I use the List view to render a list. The problem is when I click the Find tab. The List view does not render. I have to first swipe the screen, then the List view show.
I used connect of redux-react to map the dispatch to FindScreen component. I request the data source of the List view in the componentDidMount lifecycle hook.
componentWillReceiveProps(nextProps) {
if( nextProps.doctorList !== this.props.doctorList){
debugger;
this.setState({
isRefreshing: false,
dataSource: this.state.dataSource.cloneWithRows(nextProps.doctorList),
})
}
}
As the code above, I set the debugger in the componentWillReceiveProps lifecycle hook. The breakpoint stops at the line of the debugger. Now, I know I request the data from the backend well.
Do you know the reason of the List view does not render?
What can I do to show the List view in the first render?
I know one way of solving this problem is change lazy: false, to lazy: true. Due to the lazy: false is written by my leader, so I had better not change it.
Add removeClippedSubviews={false} to your ListView.
You can refer to https://github.com/react-community/react-navigation/issues/1279 for the fix.
Please note that this is not an ideal fix because this is disabling a performance optimization.
You can read about the performance optimization here https://facebook.github.io/react-native/docs/listview.html#removeclippedsubviews