How to call style from constant file react native? - javascript

I have a file register.js with some UI component.
import CustomHeader from '../components/Header';
...
static navigationOptions = ({navigation, navigation: { state } }) => {
return {
title: '',
headerStyle: CustomHeader
}
};
I try to create and call CustomHeader style from another constant file.
import { getStatusBarHeight } from "react-native-safearea-height";
import { Platform } from 'react-native';
var iosMarginTop = getStatusBarHeight(true);
const headerStyle = ({backgroundColor = '#000'}) => {
backgroundColor: backgroundColor,
marginTop: Platform.OS == 'ios' ? iosMarginTop : 0
}
export default headerStyle;
How can i dynamically call customHeader style and pass some parameter for specific UI style for example backgroundColor? and by default, if none parameter passed, it will remain default value "#000"

Update your code like this,
const headerStyle = ({backgroundColor}) => {
backgroundColor: backgroundColor ? backgroundColor : "#000",
marginTop: Platform.OS == 'ios' ? iosMarginTop : 0
}

Related

React-spring not animating as expected

So I'm using react-visibility-sensor with react-spring to animate text sliding char by char from any side I want.
In my home page the animation is running smoothly, I use it twice one from the right side and another from the top side.
When I switch routes and go to another page the animation does not work.
I have my code divided in an "Title" component "Char" component and a custom hook "useAnimatedText".
Title component:
import React from "react";
import VisibilitySensor from "react-visibility-sensor";
import useAnimatedText from "../../hooks/useAnimatedText";
import Char from './Char'
const Title = ({title, side}) => {
// HERE I CALL A CUSTOM HOOK THAT WILL DIFINE IF THE ELEMENT IS VISIBLE OR NOT
// AND HANDLE THE ANIMATION WHEN NECESSARY
const [isVisible, onChange, objArray] = useAnimatedText(title)
let elements = objArray.map((item, i) => {
return(
<Char
key={i}
isVisible={isVisible}
item={item}
delay={400 + (i * 40)}
side={side}
/>
)
})
console.log(isVisible)
return(
<VisibilitySensor onChange={onChange} >
<span className="title-box">
<h1 className="my-heading divided-heading">
{elements}
</h1>
<hr className="title-ruller"></hr>
</span>
</VisibilitySensor>
)
}
export default Title
Char component:
import { useSpring, animated } from "react-spring"
const Char = (props) => {
const { isVisible, item, delay, isBouncy, side} = props
const [ref, addBounce] = useBounce()
let springConfig = {}
if (side === 'right') {
springConfig = {
to: {
opacity: isVisible ? 1 : 0,
translateX : isVisible ? '0px' : '1000px'
},
config: { mass:2, tension: 200, friction: 30},
delay: delay
}
}
else if (side === 'top') {
springConfig = {
to: {
opacity: isVisible ? 1 : 0,
translateY: isVisible ? '0px' : '-500px'
},
config:{ mass:2, tension: 250, friction: 35},
delay: delay
}
}
const spring = useSpring({...springConfig})
return(
<animated.span
style={ spring }
className={isVisible ? 'is-visible' : 'is-not-visible'}
>
{item.char === ' ' ? <span> </span> : item.char}
</animated.span>
)
}
export default Char
This is the custom Hook:
import { useState } from "react";
import { stringToArray } from '../helpers'
// HOOK THAT HANDLES THE TEXT ANIMATION BY SETTING A STATE OF VISIBILITY
function useAnimatedText(string) {
const [isVisible, setVisibility] = useState(false);
const onChange = visiblity => {
visiblity && setVisibility(visiblity);
};
let objArray = stringToArray(string)
return [isVisible, onChange, objArray]
}
export default useAnimatedText
I did a console.log(isVisible) and the value was true but it was rendering in the page the spring values as if it was false(not visible).
I really canĀ“t understand where I'm going wrong here, the only problem I have is when I'm not at my main route, could it be because of react-router-dom?
If someone has any clue, let me know.

Why do I get Failed prop type: Invalid prop `onAnimationFinish` of type `object` supplied to `LottieView`, expected a `funtion`

I am pretty sure am supplying a function to the LottieView component, but am getting the aforementioned console warning error: Failed prop type: Invalid prop onAnimationFinish of type object supplied to LottieView, expected a function., telling me I supplied an object. Here below is part of my code affiliated with the issue:
import React from "react";
import { View, StyleSheet, Modal } from "react-native";
import * as Progress from "react-native-progress";
import LottieView from "lottie-react-native";
import colors from "../config/colors";
function UploadScreen(onDone, progress = 0, visible = false) {
return (
<Modal visible={visible}>
<View style={styles.container}>
{progress < 1 ? (
<Progress.Bar
color={colors.primary}
progress={parseInt(progress)}
width={200}
/>
) : (
<LottieView
autoPlay
loop={false}
onAnimationFinish={onDone}
source={require("../assets/animations/done.json")}
style={styles.animation}
/>
)}
</View>
</Modal>
);
}
const styles = StyleSheet.create({
animation: { width: 150 },
container: {
alignItems: "center",
flex: 1,
justifyContent: "center",
},
});
export default UploadScreen;
And the component consuming the UploadScreen component is as follows:
import { StyleSheet } from "react-native";
import React, { useState } from "react";
import * as Yup from "yup";
import {
Form,
FormField,
FormImagePicker,
FormPicker as Picker,
SubmitButton,
} from "../components/forms";
import listingsApi from "../api/listings";
import Screen from "../components/Screen";
import CategoryPickerItem from "../components/CategoryPickerItem";
import useLocation from "../custom_hooks/useLocation";
import UploadScreen from "./UploadScreen";
const validationSchema = Yup.object().shape({
title: Yup.string().required().min(1).label("Title"),
price: Yup.number().required().min(1).max(10000000).label("Price"),
description: Yup.string().label("Description"),
category: Yup.object().required().nullable().label("Category"),
images: Yup.array().min(1, "Please select at least one image!"),
});
const categories = [
{
backgroundColor: "#fc5c65",
icon: "floor-lamp",
label: "Furniture",
value: 1,
},
{
backgroundColor: "#fd9644",
icon: "car",
label: "Cars",
value: 2,
},
];
function ListingEditScreen() {
const userLocation = useLocation();
const [uploadVisible, setUploadVisible] = useState(false);
const [progress, setProgress] = useState(0);
const handleSubmit = async (listing, { resetForm }) => {
setProgress(0);
setUploadVisible(true);
const result = await listingsApi.addListing(
{ ...listing, userLocation },
(progress) => setProgress(progress)
);
if (!result.ok) {
setUploadVisible(false);
return alert("Could not save the listing");
}
resetForm();
};
return (
<Screen style={styles.container}>
<UploadScreen
onDone={() => setUploadVisible(false)}
progress={progress}
visible={uploadVisible}
/>
</Screen>
);
}
export default ListingEditScreen;
You're not destructuring your props. The first argument to UploadScreen is the entire props object:
// onDone is your entire props object here.
function UploadScreen(onDone, progress = 0, visible = false) {
Add braces to pull out specific props:
// add the curlies to extract specific props
function UploadScreen({onDone, progress = 0, visible = false}) {
Destructure the props
function UploadScreen({onDone, progress, visible}) {

Applying conditional styles to a component in React - Inline CSS

I am trying to style some buttons based on whether they are 'active' or not, and also whether or not the use is hovering the mouse over them.
It works to some extent, however, it's behaving in a way that I don't fully understand.
How do I apply a conditional style to a component, based on its state, as well as based on user behavior?
I have an example in this SANDBOX
And the main JS file copied here:
demo.js
import React from "react";
import PropTypes from "prop-types";
//import { makeStyles } from "#material-ui/core/styles";
import { withStyles } from "#material-ui/styles";
import { Button } from "#material-ui/core";
const useStyles = theme => ({
root: {
backgroundColor: theme.palette.secondary.paper,
width: 500
},
pageButton: {
backgroundColor: "black",
color: "blue",
width: 30,
minWidth: 20,
"&:hover": {
backgroundColor: "green"
}
},
normalButton: {
width: 30,
minWidth: 20,
backgroundColour: "red"
}
});
class Feature extends React.Component {
constructor(props) {
super(props);
this.state = { currentPage: 0 };
}
handleClick(page) {
this.setState({ currentPage: page });
}
fetchPageNumbers() {
return [1, 2, 3];
}
render() {
const classes = this.props.classes;
return (
<div className={classes.root}>
{this.fetchPageNumbers().map((page, index) => {
return (
<div>
<Button
onClick={() => this.handleClick(page)}
key={page}
className={
this.state.currentPage === page
? classes.pageButton
: classes.normalbutton
}
>
{page}
</Button>
<Button
onClick={() => {}}
key={page * 20}
className={classes.normalButton}
>
{page * 20}
</Button>
</div>
);
})}
</div>
);
}
}
Feature.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(useStyles)(Feature);
There are two rows. The second row picks up the styles just fine.
The first row will only adhere when the button is clicked. I want to be able to set the state based on whether the current button is active (ie. state == buttonNumber), and also whether or not the user is hovering over any of the buttons.
How do I apply a conditional style to a component, based on its state, as well as based on user behavior?
For conditional style based on user behavior
I guess your current demand is when it's hovering.
"&:hover": {
// Hover styles
}
For conditional style based on params(props)
withStyles doesn't have access to the properties.
refer: issue: Can withStyles pass props to styles object? #8726
But there are multiple work-around solutions
1.use injectSheet HOC
notice that the useStyles in your code is actually not a hook
const styles = props => ({
root: {
width: props.size === 'big' ? '100px' : '20px'
}
})
or
const styles = {
root: {
width: props => props.size === 'big' ? '100px' : '20px'
}
}
with
const CustomFeature = ({size, classes}) => <Feature className={classes.root} />;
export default withStyles(styles)(CustomFeature);
2.use style hooks with params (for functional components)
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles(theme => ({
root: {
width: props => props .size === "big" ? "100px" : "20px"
}
}));
const classes = useStyles();
or
import { makeStyles } from "#material-ui/core/styles";
const useStyles = params =>
makeStyles(theme => ({
root: {
width: params.size === "big" ? "100px" : "20px"
}
}));
const classes = useStyles(whateverParamsYouWant)();
In response to #keikai you can also pass in an object into the styles() hook (I was getting an error by just passing in props).
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles(theme => ({
root: {
width: ({ size }) => (size === "big" ? "100px" : "20px")
}
}));
const classes = useStyles({ size });

It is possible to change the text color depending on the value? (React native)

I am working in an app using React native, here goes the code that I am in trouble:
import React, { Component } from "react";
import { Text, StyleSheet } from "react-native";
import { Content, Card, CardItem, Body, Left } from "native-base";
import { PricingCard } from "react-native-elements";
export default class AppBodyData extends Component {
render() {
let articles = this.props.data.map(function (articleData, index) {
return (
<PricingCard
//color='#ff3300'
wrapperStyle={
articleData.percent_change_1h >= 0 ? styles.green : styles.red
}
info={[
"1h change: " + articleData.percent_change_1h,
"24h change: " + articleData.percent_change_24h,
"7days change: " + articleData.percent_change_7d,
]}
button={{
title: "More information",
icon: "info",
backgroundColor: "#4f9deb",
}}
/>
);
});
return <Content>{articles}</Content>;
}
}
const styles = StyleSheet.create({
green: {
color: "#00ff00",
},
red: {
color: "#ff0000",
},
});
module.export = AppBodyData;
What I need is that if the articleData.percent_change_1h variable is positive the color of that variable must be green otherwise must be red.
PricingCard is an object of react-native-elements library: https://react-native-training.github.io/react-native-elements/API/pricing/
Thanks in advance
You could use a ternary operator to manipulate styles passed to your PricingCard's wrapperStyle prop.
// Stylesheet.
import { StyleSheet } from 'react-native'
// Card.
<PricingCard wrapperStyle={(articleData.percent_change_1h >= 0) ? styles.green : styles.red} ../>
// Styles.
const styles = Stylesheet.create({
green: {
color: '#00ff00'
},
red: {
color: '#ff0000'
}
})

Redux state not getting received as expected

I'm using redux for the first time and something subtle is getting by me.
I have a container called Dashboard that displays two SimpleTabs. A simple tab is component that gets pressed and returns a number to its container for the item pressed. I can see actions being dispatched, event handler firing etc but the state being received in mapStateToProps never contains the item values. This might be why the render is never getting fired because the state is not changed.
Note: I've used the Ignite boilerplate as a starting point. It makes use of reduxsauce so the DashboardRedux.js may look a little unusual.
Dashboard.js
import React, { Component } from 'react'
import { ScrollView, Text, View, Image, TouchableOpacity, StyleSheet } from 'react-native'
import moment from 'moment'
import { Images, Colors, Metrics, ApplicationStyles } from '../Themes'
import SimpleTab from '../Components/SimpleTab'
import DashboardHeader from '../Components/DashboardHeader'
import DashboardActions from '../Redux/DashboardRedux'
import { connect } from 'react-redux'
export class Dashboard extends Component {
//TODO make numbers into enums
constructor(props) {
super(props)
this.updateTimeframe = this.updateTimeframe.bind(this)
this.updateAnalysisView = this.updateAnalysisView.bind(this)
const curTimeframe = 0
const curAnalysisView = 0
this.state = {curTimeframe, curAnalysisView}
}
// Event handler for timeframe tab
updateTimeframe(newValue) {
//newValue gets received as expected
this.props.updateTimeframe(newValue)
}
// Event handler for analysisview tab
updateAnalysisView(newValue) {
this.props.updateAnalysisView(newValue)
}
getUpdateTime = () => {
let s = moment().format("h:mm a")
return s
}
// Takes us back to login
openLoginScreen = () => {
//TODO does navigater have notion of <back>?
this.props.navigation.navigate('LoginScreen')
}
// For info on flex: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
render () {
let styles = ApplicationStyles.screen
/*
let localStyles = StyleSheet.create({
container: {
paddingBottom: Metrics.baseMargin
},
centered: {
alignItems: 'center'
}
})
console.log(styles)
*/
return (
//Problem: this.props.curTimeframe is always undefined
<View style={styles.mainContainer}>
<DashboardHeader updateTime={this.getUpdateTime()}></DashboardHeader>
<View style={{justifyContent: 'space-between'}} >
<SimpleTab
onSelect={this.updateTimeframe}
curTab={this.props.curTimeframe}
tabNames={["TODAY", "1W", "1M", "3M", "6M"]}
/>
</View>
<View style={{flex:1}} >
<Text style={{color: Colors.snow}}>
Analytical stuff for {this.props.curTimeframe} and {this.props.curAnalysisView}
</Text>
</View>
<View style={{height:60, justifyContent: 'space-between'}} >
<SimpleTab
onSelect={this.updateAnalysisView}
curTab={this.props.curAnalysisView}
tabNames={["HOME", "DAYPART", "REC", "INGRED", "SETTINGS"]}
/>
</View>
</View>
)}
}
const mapStateToProps = (state) => {
// Problem: state passed never contains curAnalysisView or curTimeframe
return {
curAnalysisView: state.curAnalysisView,
curTimeframe: state.curTimeframe
}
}
const mapDispatchToProps = (dispatch) => {
return {
updateTimeframe: newValue => dispatch(DashboardActions.updateTimeframe(newValue)),
updateAnalysisView: newValue => dispatch(DashboardActions.updateAnalysisView(newValue))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard);
DashboardRedux.js
import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'
/* ------------- Types and Action Creators ------------- */
const { Types, Creators } = createActions({
updateTimeframe: ['newValue'],
updateAnalysisView: ['newValue'],
})
export default Creators
export const DashboardTypes = Types
/* ------------- Initial State ------------- */
export const INITIAL_STATE = Immutable({
curTimeframe: 0,
curAnalysisView: 0
})
/* ------------- Reducers ------------- */
export const updateTimeframe = (state, {newValue}) => {
//newValue gets passed as expected
return state.merge({curTimeframe: newValue});
}
export const updateAnalysisView = (state, {newValue}) => {
return state.merge({curAnalysisView: newValue});
}
/* ------------- Hookup Reducers To Types ------------- */
export const reducer = createReducer(INITIAL_STATE, {
[Types.UPDATE_TIMEFRAME]: updateTimeframe,
[Types.UPDATE_ANALYSIS_VIEW]: updateAnalysisView
})
SimpleTab.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { View, Text, Image, StyleSheet, TouchableHighlight } from 'react-native'
import { Colors, Metrics, Fonts, Images } from '../Themes/'
import styles from '../Themes/ApplicationStyles'
export default class SimpleTab extends Component {
static defaultProps = {
onSelect: null,
curTab: 0,
tabNames: ["Tab1", "Tab2", "Tab3"]
}
static propTypes = {
onSelect: PropTypes.func,
curTab: PropTypes.number,
tabNames: PropTypes.array
}
tabSelected = (tabNum) => {
this.props.onSelect(tabNum);
}
renderTabBar = () => {
let localStyles = StyleSheet.create({
unselectedText: {
marginTop: Metrics.baseMargin,
marginHorizontal: Metrics.baseMargin,
textAlign: 'center',
fontFamily: Fonts.type.base,
fontSize: Fonts.size.regular,
color: Colors.snow
},
selectedText: {
marginTop: Metrics.baseMargin,
marginHorizontal: Metrics.baseMargin,
textAlign: 'center',
fontFamily: Fonts.type.base,
fontSize: Fonts.size.regular,
fontWeight: 'bold',
color: Colors.fire
}
})
let result = []
for (i=0; i<this.props.tabNames.length; i++) {
let tabStyle = (i == this.props.curTab) ? localStyles.selectedText : localStyles.unselectedText
result.push(
<TouchableHighlight key={this.props.tabNames[i]} onPress={this.tabSelected.bind(this, i)}>
<Text style={tabStyle}>{this.props.tabNames[i]}</Text>
</TouchableHighlight>
)
}
return result
}
render () {
console.log("rendering tab")
return (
<View flexDirection='row' style={styles.contentContainer}>
{this.renderTabBar()}
</View>
)
}
}
MapStateToProps receives the new state properties via reducers. Your MapStatetoProps in Dashboard.js should look like below to get the new values.
const mapStateToProps = (state) => {
// Problem: state passed never contains curAnalysisView or curTimeframe
//new state values should be accessed via reducers..
return {
curAnalysisView: state.updateAnalysisView['curAnalysisView'],
curTimeframe: state.updateTimeframe['curTimeframe']
}
}
the mapStateToProps should like:
const mapStateToProps = (state) => {
const stateObj = state.toJS()
return {
curAnalysisView: stateObj.curAnalysisView,
curTimeframe: stateObj.curTimeframe
}
}
the .toJS() function converts it from immutable object to JS object.
Also, the reducer should have a default case that just returns the current state for when there is no action passed.
It turned out I needed to specify the "dashboard" branch of the state tree like this:
const mapStateToProps = (state) => {
return {
curAnalysisView: state.dashboard.curAnalysisView,
curTimeframe: state.dashboard.curTimeframe
}
}

Categories

Resources