React Native: Conditionally Render Components - react-native

I've searched this question and found a solution that said to conditionally render based on the state as follows:
render() {
const content = this.state.isReady ? <Home/> : <Splash/>;
return (
{content}
);
}
However, I keep getting an Invariant Violation: Objects are not valid a React child (found object with keys {content}.

your make typo, you returned Object, instead use between JSX elements:
const Ready = () => <div>Ready</div>
const NotReady = () => <div>NotReady</div>
class App extends Component {
constructor() {
super();
this.state = {
isReady: false
};
}
render() {
const content=this.state.isReady ? <Ready /> : <NotReady />
return (
<div>
{content}
</div>
);
}
}

Use simple if else instead of ternary expression because sometimes ternary operators "return" whatever's inside and can't execute blocks of code.
if (this.state.isReady) {
return <Home />
} else {
return <Splash />
}

Related

How to open/close ExpandableCalendar of react-native-calendars programmatically?

I want to open/close ExpandableCalendar programmatically. I found there's only an initialPosition prop. It's not working when changing initialPosition. So I tried to use ref and call setPosition() function of ExpandableCalendar
export const MyScreen = () => {
const ref = useRef<ExpandableCalendar>()
return (
<CalendarProvider date={new Date()}>
<ExpandableCalendar ref={ref} />
</CalendarProvider>
)
}
when I use this code, the ref.current.contentRef is always undefined
My Question is
How to get the ref of ExpandableCalendar?
It seems the asCalendarConsumer saves the ref as contentRef:
function asCalendarConsumer(
WrappedComponent: React.ComponentType<any>
): React.ComponentClass {
class CalendarConsumer extends Component {
contentRef: any;
saveRef = (r: Ref<React.Component<any>>) => {
this.contentRef = r;
};
render() {
return (
<CalendarContext.Consumer>
{(context) => (
<WrappedComponent
ref={this.contentRef}
context={context}
{...this.props}
/>
)}
</CalendarContext.Consumer>
);
}
}
hoistNonReactStatic(CalendarConsumer, WrappedComponent);
return CalendarConsumer;
}
export default asCalendarConsumer;
/* ExpandableCalendar */
export default asCalendarConsumer(ExpandableCalendar);
Is there a way to open ExpandableCalendar programmatically? Does the setPosition() function work or there's another way to do this.
My Environment is
react-native-calendars#1.1266.0:
react-native#0.64.2:

asynchronous function in render() method fails (Invariant Violation)

I'm trying to use an asynchronous function in render():
async _check() {
const token = await AsyncStorage.getItem('myToken');
if(token !== null) {
this.props.navigation.navigate('My Screen', {token: token});
}
else {
return (
<View style={styles.content_container}>
...
</View>
);
}
}
render() {
return (
<View>
{ this._check() }
</View>
);
}
but I'm getting this error:
Invariant Violation: Invariant Violation: Objects are not valid as a React child (found: object with keys {_40, _65, _55, _72}). If you meant to render a collection of children, use an array instead.
Can someone tell me what's wrong with my code ?
You can't use any asynchronous functions or do any sideffects (like navigating) in render. This is directly against React principles. Render should only be rendering elements from props and state. Aside from that, error you are getting is because you are rendering result of async function, which is always a Promise. Also, getting token from AsyncStorage on every render doesn't make sense as render will happen often, up to few times per second
Put your logic into lifecycle methods e.g. componentDidMount, then use this.setState to change state the way you want, and use this.state to render your component in render()
class SomeComponent extends Component {
constructor(props) {
super(props)
this.state = {
message: ''
}
}
async componentDidMount() {
const token = await AsyncStorage.getItem('myToken')
if (token !== null) {
this.props.navigation.navigate('My Screen', { token: token })
} else {
this.setState({ message: 'token is missing' })
}
}
render() {
return (
<View style={styles.content_container}>
<Text>{this.state.message}</Text>
</View>
)
}
}

Why react-router-native does not render my component?

Trying to implement a protectedRoute utils for react-native project, which basicly looks for JWT. First it shows loading indicator, and if there is no JWT present it would redirect to /login.
const LoadingComponent = () => (
<View>
<ActivityIndicator/>
</View>
)
class PrivateRoute extends React.Component {
state = {
loading: true,
jwt: null,
}
componentDidMount() {
storage.retrieve('JWT').then(jwt => this.setState({ loading: false, jwt }))
}
render() {
const { children } = this.props;
const { jwt, loading } = this.state;
if (loading) {
return <Route {...children} component={LoadingComponent}/>
}
if (!jwt) {
return <Redirect to="/signup" />;
}
return <Route {...children} />
}
}
export default PrivateRoute;
this.props.children has all the required information to make a Route in the application. The original idea is that in case of loading we would just overwrite this.props.children.component with custom loading screen.
BUT the solution which does not give me error is (only warning):
if (loading) {
return LoadingComponent
}
I have tried also to manually inline component as
component={() => <View>{...}</View>
render={() => ...}
However it also ends up as the same error. Invariant Violation: Element type is invalid: expected a string ..... but got: undefined

how can i set a state variable as component's property in react native?

i started learning react native and building an android app.so i have facing some issue with setting and getting a component's property.here is my code
i have two components named as content-container and bar-chart.
inside content-container ,here is my code block:
state = {
barChartResponse: {},
arcChartResponse: {},
stackChartResponse: {},
lineChartResponse: {},
token:'abc',
};
componentWillMount() {
this.setState({token:'xyz'});
}
render() {
return (
<ScrollView>
<BarChart chartData = {this.state.token} />
</ScrollView>
);
}
now i am trying to get this property inside bar-chart component as follows:
constructor(props) {
super(props);
Alert.alert("ChartData is : ",props.chartData);
}
it displays me value what i set in state object by default i.e. abc, but i want updated value.
please help me to find out what am i doing wrong....... thanks in advance.
You can use componentWillRecieveProps but it is deprecated and in RN>54 you can use componentDidUpdate or getDerivedStateFromProps to get state from parent like this:
componentDidUpdate(nextProps){
if (this.props.chartData !== nextProps.chartData) {
alert(nextProps.chartData)
}
}
or
static getDerivedStateFromProps(props, current_state) {
if (current_state.chartData !== props.chartData) {
return {
chartData: props.chartData,
}
}
}
You need to update state of parent component it will automatically reflect in child component but next time you will receive in componentWillRecieveProps(nextProps) then render method.
for example:
state = {
barChartResponse: {},
arcChartResponse: {},
stackChartResponse: {},
lineChartResponse: {},
token:'abc',
};
componentWillMount() {
this.setState({token:'xyz'});
}
updateState = () => {
this.setState({token: "newToken"})
}
render() {
return (
<ScrollView>
<Button onPress={this.updateState}>update State</Button>
<BarChart chartData = {this.state.token} />
</ScrollView>
);
}
in BarChart.js
componentWillRecieveProps(nextProps) {
// you can compare props here
if(this.props.chartData !== nextProps.chartData) {
alert(nextProps.chartData)
}
}

initialValues not loading in redux-form

I'm probably using this wrong but I'm trying to get a redux form to load with initialValues which isn't working. I've got a container component which renders a form:
class ProductScreen extends Component {
render() {
return (
<ProductForm {...this.props} {...this.state} />
)
}
}
const mapStateToProps = (state) => {
return {
initialValues: {name: 'Ferrari'}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ProductScreen)
For the ProductForm component the render() method includes a Field which loads a simple component. Note that it's a single field of name being name. I'm initialising the reduxForm the usual way but when the screen loads the form field isn't being populated with the expected "Ferrari" value:
// importing functions from redux-form
import { Field, reduxForm } from 'redux-form/immutable'
// inside the render() function
<Field component={renderInput} name='name' ref='name' placeholder='Product name' />
const ProductForm = reduxForm({
form: 'createProduct',
enableReinitialize: true
})(ProductFormComponent)
const renderInput = ({input, ...inputProps}) => {
return (
<TextInput {...inputProps} {...input} />)
}
In the React native debugger if I console out the renderInput function I can see the 'Ferrari' value in inputProps.meta.initial but not in input.value
I think you are returning it at wrong place.
Try the following code snippet:
const ProductForm = reduxForm({
form: 'createProduct',
initialValues: {name: 'Ferrari'},
enableReinitialize: true
})(ProductFormComponent)