react-native module export type - reactjs

I love RN but one issue that is really annoying me is lack of conventions. I'm used to it a bit as a js developer. But using ES6 or not
render() { vs. render: function() {
is one thing. What I really can't understand is when I saw the WebView module export example as
exports.examples = [
{
title: 'WebView',
render(): ReactElement { return <WebViewExample />; }
}
];
And sometimes I see
export default PDFView;
I'm used to
module.exports = WebViewExample
Returning an object breaks my code and forces me to think about what type I should expect from each component. I understand the value of returning an object but it seems like a bad thing to start introducing in the docs. End of rant. What is default is for?

Related

Typescript useState React Hook Destructuring Error (Not Returning Array?)

I'm futzing about with a simple React app for the first time, and looking to set up a simple MVC to connect with an ASP.NET backend, all being done in Visual Studio 2019 (which has caused some headaches with React). However, now that I'm trying to implement models, I'm finding that all of the suggestions for strongly typing the useState hook aren't working for me.
According to a few tutorials like this one or this one, it should be as simple as adding a type in brackets, like const [state, setState] = useState<Type>({}), since it has a generic implementation. Unfortunately, for me, this throws the error "Uncaught TypeError: Invalid attempt to destructure non-iterable instance."
This thread here suggested that switching from an array to an object by changing the [] to {}, however that simply made the two parameters I passed be undefined, so I had no state or way to update said state.
I went down the path of reading until I had a brief understanding of array destructuring, so I understand that the idea is to pass an array with two constants that will be assigned in-order the elements of the array returned by the useState hook. So, I tried manually destructuring the array, setting a constant useState[0] and useState[1] separately. When I tried this for an untyped hook, it worked as expected. When I tried this for the typed hook, I got some errors about there not being elements, and upon printing out the object, found not an array like the untyped hook, but a boolean. It seems that a typed useState is returning the value "false" instead of an array.
At this point, my best guess is that I have some dependencies that don't implement the typed useState, but I'm really hitting a stone wall on troubleshooting. Anyone have some idea on what I'm doing wrong?
Edit: The testing file I have set-up -
import React, { useState } from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import { Product } from '../Models/Product';
const Account = () => {
//Works as-intended
const test = useState(5);
//Returns false when logged
const test2 = useState<Product>({
"ProductID": "p#corn", "Description": "Delicious corn", "ImageLink": "https://testlink.com", "Name": "Corn", "Price": "2.99", "Category": "Food"
});
//What should work, to my understanding, however this makes the route crash when it's navigated to because of the "Inavlid attempt to destructure non-iterable instance
const [test3, setTest] = useState<Product>({});
function clickHandler() {
console.log(test)
}
function clickHandler2() {
console.log(test2)
}
return (
<div className='wrapper'>
<button onClick={clickHandler}>Test</button>
<button onClick={clickHandler2}>Test2</button>
</div>
)
}
export default Account;
The Product model -
export interface Product {
ProductID: string;
Description: string;
ImageLink: string;
Name: string;
Price: string;
Category: string;
}
Here's a CodeSandbox with an example somewhat related to your case, which demonstrates how useState is meant to work on everyone else's machine.
As you will see from testing it and messing with the example I shared, useState with a generic type specified should be fine and dandy and behave just as you expect.
That underlines that there's something about your local machine or project environment which is special to you.
import React, { useCallback, useState } from "react";
import "./styles.css";
interface Product {
Name: string;
Price: number;
}
const productA = {
Name: "Corn",
Price: 2.99
};
const productB = {
Name: "Frozen Orange Juice",
Price: 10_000
};
export default function Show() {
const [product, setProduct] = useState<Product>(productA);
const toggleProduct = () =>
setProduct(product === productA ? productB : productA);
return (
<div className="App" onClick={toggleProduct}>
<h1>{product.Name}</h1>
<h2>{product.Price}</h2>
</div>
);
}
Since you asked about how to get the best responses...
Ideally when posting try to create a problem case which other people can see failing. If you attempt to do this (e.g. using a CodeSandbox) but it works fine there, then it's a matter of working on cleaning up your own local environment until you figure out what is unique about your setup which makes code break for you but no-one else.
Ideally if you can't create it within a single page repro (sandbox), because it's something to do with your project structure, create a runnable reproduction by sharing the actual project structure and its code and configuration publically on github so people can recreate your problem by checking it out and building/running it. That way they will soon be able to track down what's distinctive about your project.
Often this process of creating a repro will help you figure out the problem anyway - e.g. you start with a vanilla create-react-app typescript skeleton from https://create-react-app.dev/docs/adding-typescript/ to populate a blank github repo and your problem case suddenly starts working there - now you have a basis for bisecting your problem by adding your project's special features to the simple repro until it breaks.

Reuse react's PropTypes in tests and other parts of code?

Is there an easy/straightforward way to re-use the validation built in to React.PropTypes progrmatically in tests and other code?
For example, if I have:
ButtonX.propTypes = {
className: React.PropTypes.string
};
If I load that button with a numerical classname, react will warn in the console.
I would like to re-use all that logic in code, and do something like:
validateButtonUsingReactPropTypes({ className: 'my-class' })
Is there a known clean way of getting acces to those internals?
Check out the Test Utilities article in the docs... It think it would provide some examples of how you can access the validators for testing.
Example using renderIntoDocument, based on code from ReactJSXElementValidator-test.js in the React GitHub repository.
// arrange
RequiredPropComponent = class extends React.Component {
render() {
return <span>{this.props.prop}</span>;
}
};
RequiredPropComponent.displayName = 'RequiredPropComponent';
RequiredPropComponent.propTypes = {prop: React.PropTypes.string.isRequired};
// act
ReactTestUtils.renderIntoDocument(<RequiredPropComponent prop={null} />);
// assert
let testPassed = console.error.calls.count() == 0
You can obviously incorporate this into some good testing tools, but this is just the raw call.

How do properly use Onsen's Navigator in React?

I'm trying to implement a simple Onsen Navigator in React.
So far I'm receiving an error 'route is not defined' and I was looking through the examples & docs but I only saw the initialRoute prop was provided, how & where does the route prop generated or something? Cause it seems like its not specified.
Here is my the code of my component:
import React, {PropTypes} from 'react';
import ons from 'onsenui';
import * as Ons from 'react-onsenui';
class SignUp extends React.Component {
constructor(props) {
super(props);
this.state = {
index : 0
};
this.renderPage = this.renderPage.bind(this);
this.pushPage = this.pushPage.bind(this);
}
pushPage(navigator) {
navigator.pushPage({
title: `Another page ${this.state.index}`,
hasBackButton: true
});
this.setState({index: this.state.index++});
}
renderPage(route, navigator) {
return (
<Ons.Page key={route.title}>
<section style={{margin: '16px', textAlign: 'center'}}>
<Ons.Button onClick={this.pushPage}>
Push Page
</Ons.Button>
</section>
</Ons.Page>
);
}
render() {
return (
<Ons.Page key={route.title}>
<Ons.Navigator
renderPage={this.renderPage}
initialRoute={{
title: 'First page',
hasBackButton: false
}}
/>
</Ons.Page>
);
}
};
SignUp.propTypes = {
'data-pageName': PropTypes.string.isRequired
};
export default SignUp;
Is this the right syntax in ES6? Have I missed something?
When using Ons.Navigator in react the two required properties are:
initialRoute - it should be an object.
renderPage - method which receives 2 arguments - route and navigator. The route should be an object similar to the initialRoute one. You provide that object when you are calling pushPage and similar methods.
It seems that you already know these 2, but there still 2 other things which you need to be careful about. They are not directly onsen related, but come up a lot when using react in general.
Whenever you have a list of dom elements (for example an array of Ons.Page tags) each of those should have a unique key property.
Whenever you use a method you need to make sure you are binding it if you need some extra arguments.
It seems you also know these two. So the only thing left is to make sure you follow them.
Your syntax is correct - the only thing missing is the route variable in SignUp.render. Maybe you originally copied the renderPage method and that is how you have a leftover Ons.Page.
If you're not putting the SignUp component inside some other navigator, tabbar or splitter then you don't actually need the Ons.Page in its render method. Those are the only cases when they are needed. If you it happens to have one of those components as a parent then you can just specify the key.
PS: I think there should be a React Component Inspector (something like this) which you can install - then I think you may be able to see the place where the error occurs. I think if you knew on which line the problem was you would have been able to solve it. :)
For me, with the object I was passing to initialRoute(), it needed a props property, which itself was an object with a key property. See the before and after below.
Before fixing
render() {
return (
<Navigator
initialRoute={{component: DataEntryPage}}
renderPage={this.renderPage}
/>
);
}
}
This was causing the following console warning:
Warning: Each child in an array or iterator should have a unique "key" prop.
Check the render method of `Navigator`.
After fixing
render() {
return (
<Navigator
initialRoute={{component: DataEntryPage, props: {key: 'DataEntryPage'}}}
renderPage={this.renderPage}
/>
);
}
}
Notice that the difference I needed to make was the addition of , props: {key: 'DataEntryPage'}.
Feel free to check out this medium article for more information.

Using React.createClass instead of ES6 Classes (extends React.Component)?

Is there any harm in using React.createClass to define my components instead of using the ES6 approach where I extend from React.Component?
Below is an example where the Circle component is created using React.createClass and the Circle2 component is created using the ES6 class approach:
var Circle = React.createClass({
render: function() {
return (
<p>Hello</p>
);
}
});
class Circle2 extends React.Component {
render() {
return <p>Hello</p>;
}
}
I have read about the technical differences between both approaches, but am I doing something wrong by telling myself (and others) that using React.createClass is totally OK?
Thanks,
Kirupa
There's no harm in using React.createClass. It's still the official suggestion in the docs and the unofficial suggestion from the devs.
In fact, I'd go as far as to say that I think it's still a better solution than classes, for a few reasons.
Classes don't autobind (without hacks).
Adding static props is not intuitive.
You need third party libraries for mixins.
There are different lifecycle methods.
Object literal syntax is a very intuitive way to define properties and most Javascript developers will be very comfortable with it already.
I've heard it argued that the class syntax is more elegant, but with object literal shorthand and arrow functions, calls to createClass can be pretty expressive too.
const Circle = React.createClass({
render() {
return (
<p>Hello</p>
);
}
});
Of course, more than either of the others you should look for opportunities to use stateless functions instead.
const Circle = (props) => <p>Hello</p>;
They're the simplest option and they resolve a lot of the ambiguity above by simply not including it. It's just a function that takes props as arguments.

Scoping 'this' within a reactjs component

While building my first reactjs component, I got the familiar "undefined is not a function" when trying to use a helper (makeWorkSiteUrl) because the this scope had changed away from being that of the component.
Of course, I just did what most JS developers would do and declared that=this before I made my function call to solve the problem.
However, it occurred to me that this is probably a common problem. So there might be a 'better' or 'react' way of achieving the same thing. Or, it may be an indication of poor design of this component. Is there a style or method that is preferred or available instead of that=this to access a components internal functions/properties?
"Undefined is not a function":
var WorkSiteQuickList = React.createClass({
propTypes: {
data: React.PropTypes.object.isRequired
},
render() {
var workSiteNodes = this.props.data.work_sites.map(function (worksite) {
var linkUrl = this.makeWorkSiteUrl(worksite.id) //Fail
return (
<WorkSiteQuickListItem workSiteName={worksite.name} linkUrl={linkUrl} />
);
});
return (
<div>
{workSiteNodes}
</div>
);
},
makeWorkSiteUrl(workSiteId) {
return "/worksite/"+ workSiteId;
}
});
Works as expected:
var WorkSiteQuickList = React.createClass({
propTypes: {
data: React.PropTypes.object.isRequired
},
render() {
that = this;
var workSiteNodes = this.props.data.work_sites.map(function (worksite) {
var linkUrl = that.makeWorkSiteUrl(worksite.id) //OK
return (
<WorkSiteQuickListItem workSiteName={worksite.name} linkUrl={linkUrl} />
);
});
return (
<div>
{workSiteNodes}
</div>
);
},
makeWorkSiteUrl(workSiteId) {
return "/worksite/"+ workSiteId;
}
});
I'm sure this question will be closed, but I'd rather ask it than miss a critical part of the "framework".
Here are some common patterns to deal with this scoping:
Utilizing an es6 transpiler (like the JSX transformer that you're currently using, or babeljs which happens to support JSX), use arrow functions which are scoped to the outer context (aka lexical scoping).
this.props.data.work_sites.map( (worksite) => { .... return ... } )
Pass in this as the second argument of Array#map
Chain bind onto the function you pass into Array#map
function() {}.bind(this)
Update: I've had a lot of trouble lately with =>, this resolving to window when paused at a breakpoint in the chrome dev tools within the render() method. Originally I thought it was a babeljs bug. However, turns out it's actually a failure of the dev tools ability to understand that source maps actually replace this with _this.

Resources