So I'm wondering how organization and importing (require) of components is supposed to work in React Native. I have built a small app with one main TabView component in one file, and then have another file that contains the components that go under each tab. In order to bring all those into the main file, i have a whole bunch of import statements ie:
var Following = require('./viewComponents.ios');
var Trending = require('./viewComponents.ios');
var CommentButton = require('./viewComponents.ios');
var NotificationPage = require('./viewComponents.ios');
var LikeButton = require('./viewComponents.ios');
var WishLists = require('./viewComponents.ios');
var PageForProfile = require('./viewComponents.ios');
I'm having an issue where some of my components seem to be writing over each-other, and i think it is this method of importing that is doing it. For example: my PageForProfile component is:
class PageForProfile extends Component{
render(){
return(
<Text>Hello</Text>
)
}
}
But when I write a tag to display this component:
<PageForProfile></PageForProfile>
Instead of outputting text, my "Following" component is displayed in place of the "PageForProfile" component! I've gone through as much of the React literature as I can and am still at a loss. Any help would be MOST appreciated. Cheers. (p.s. new to StackOverflow - if i've broken etiquette in the way i'm asking let me know, really appreciate your community here.)
You have not posted your viewComponents.ios structure, but it's definitely wrong what you are doing. requiring the same file will always return the same object: the one that is defined in module.exports (see What is the purpose of Node.js module.exports and how do you use it?)
You have two options:
have your components defined in different files (following.ios, trending.ios etc.) and require different file for different component.
define all of the components in one file and have module.exports to return all the components as properties of object returned by module.exports (that's what React does when importing Text, View etc. ). in this case your require will look a bit differently:
{
Following,
Trending,
....
} = require('viewComponents.ios');
No idea what's in viewComponents, but you probably need to be using braces around your variable declarations, e.g.
var {Following, Trending, CommentButton} = require('./viewComponents.ios');
This destructures the object of components that viewComponents (I'm guessing) returns.
Related
I am new to react and its transpiled way of generating javascript.
In react side, I have a class Utility that uses a data object UserData organized as below -
UserDataObj.js
class UserData{
this.someobj = {};
//some function here
something(){
}
}
const UserDataObj = new UserData();
export {UserDataObj};
Utility.js
import {UserDataObj} from './data/UserDataObj';
class Utility {
doSomething(){
//UserDataObj.something();
}
}
const utility = new Utility();
export {utility};
I have another ReactApp UserApp.js, that also uses UserDataObj and Utility (although not good design wise) -
import {UserDataObj} from './data/UserDataObj';
import {utility} from './Utility';
class UserApp extends React.Component{
//does something with UserDataObj
// also does somethign with utility
}
My question is, how many utility and UserDataObj instances will be created in memory, when UserApp is rendered. My guess is, it should be only 1 instance for both. But I want to confirm if importing n times creates a new instance every time.
Any good read on this topic is greatly appreciated.
Thanks
This depends on the bundling tool, and not React. I imagine that the new browser ES Module resolution scheme works in the same way.
Most bundlers that I know of, and other import schemes such as Node.js' require module resolution will cache the import between files and always return the same exported objetcs. This is a requirement for prototype inheritance, for example, otherwise, it would mess up the instanceof operator.
That exported new Utility() instance will be the same for any module that imports it. In order to generate new instances, you would have to have a function.
Say I have a JS file contains 2 React Component class definition and a bunch of other things:
// a file called OuterComponent.react.js
import xxx from xxx;
import yyy from yyy;
// When does these run?
let a = 0;
a = 1;
export default class OuterComponent extends React.PureComponent<> {
render() {
return (
<View>
<InnerComponent />
</View>
);
}
}
class InnerComponent extends React.PureComponent<> {
//... something
}
Questions
When will the declaration and value setting code for 'a' run? Does it run when this file is imported/required by other files?
Can I have some flag in this file and changes from time to time, and then read the value of this flag from many other files? (like a singleton manager?) If I can, how do I export it and import it?
What does creating multiple files actually mean? (except that it breaks huge chunk of code into small chunks for better readability) Does it make any other difference?
Question 1: When will the declaration and value setting code for 'a' run? Does it run when this file is imported/required by other files?
Runs the first time the file is imported. It is not executed on subsequential imports.
Question 2: Can I have some flag in this file and changes from time to time, and then read the value of this flag from many other files? (like a singleton manager?) If I can, how do I export it and import it?
You can.
Exporting:
export let a = 0;
Importing:
import { a } from './filename.js';
Question 3: What does creating multiple files actually mean? (except that it breaks huge chunk of code into small chunks for better readability) Does it make any other difference?
Breaks code into small chunks;
Allows reuse; and
Enables encapsulation of non-exported variables/functions.
--
Check a demo of modules usage: http://plnkr.co/edit/0ImgQj2KzLj9O1D63Gq9?p=preview
Notice how a.js is loaded only once, even though it is imported both by b.js and c.js. Also see how it is exported and imported, and how when it changes, the change is picked up in other modules.
okay here it is
Answer 1: Yes, it runs when you import this file.
Answer 2: You can define some varible and export it to use in some other file, but that we do for constant values that does not change over time, like your action types etc, the thing you are referring to here is not what it is for, you want to use react Context or Redux store for that.
Answer 3: Creating multiple files is a modular approach to code, React emphasis on Composition that is the whole point of composing components in one another and build an App
Yes. This code will run immediately when the file is imported. It has nothing to do with react but with how js works.
You can share a variable in js using export keyword like this:
export let a = 0
Changes to this variable won't rerender your components because it's not part of any state.
Readability is huge impact by itself. It also allows reuse of variables names.
When working in collaboration it makes the flow much easier and reduces conflicts to only the places where they really are.
I know this question has been asked multiple times before but none of the solution seems to work.
I'm trying to use the library 'react-chat-popup' which only renders on client side in a SSR app.(built using next.js framework) The normal way to use this library is to call import {Chat} from 'react-chat-popup' and then render it directly as <Chat/>.
The solution I have found for SSR apps is to check if typedef of window !=== 'undefined' in the componentDidMount method before dynamically importing the library as importing the library normally alone would already cause the window is not defined error. So I found the link https://github.com/zeit/next.js/issues/2940 which suggested the following:
Chat = dynamic(import('react-chat-popup').then(m => {
const {Foo} = m;
Foo.__webpackChunkName = m.__webpackChunkName;
return Foo;
}));
However, my foo object becomes null when I do this. When I print out the m object in the callback, i get {"__webpackChunkName":"react_chat_popup_6445a148970fe64a2d707d15c41abb03"} How do I properly import the library and start using the <Chat/> element in this case?
Next js now has its own way of doing dynamic imports with no SSR.
import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(
() => import('../components/hello3'),
{ ssr: false }
)
Here is the link of their docs: next js
I've managed to resolve this by first declaring a variable at the top:
let Chat = ''
then doing the import this way in componentDidMount:
async componentDidMount(){
let result = await import('react-chat-popup')
Chat = result.Chat
this.setState({
appIsMounted: true
})
}
and finally render it like this:
<NoSSR>
{this.state.appIsMounted? <Chat/> : null}
</NoSSR>
You may not always want to include a module on server-side. For
example, when the module includes a library that only works in the
browser.
Import the library normally in child component and import that component dynamically on parent component.
https://nextjs.org/docs/advanced-features/dynamic-import#with-no-ssr
This approach worked for me.
I'll preface this question by saying I'm using Intellij IDEA.
Following this question: If external typescript modules don't have a module name, how do you avoid naming conflicts?
This is all fine and well, but let's say I'm have two Rectangle classes in two Rectangle.ts files, but in different packages, say src/utils/geom and src/utils/ui, or something like that.
src/utils/geom/Rectangle.ts has calculateSurface() as its only method and src/utils/ui/Rectangle.ts has display() as its only method.
Now if I call them both in a single file, I'll get both methods as possible calls in the type-hinting.
import GeomRectangle = require();
import UiRectangle = require();
var geom: GeomRectangle = new GeomRectangle();
var ui: UiRectangle = new UiRectangle();
// Now both those are valid
ui.calculateSurface();
ui.display();
I'm thinking it's because I'd have both Rectangle.ts files have a exports = Rectangle, since that's the name of the class and Intellij IDEA must use this export statement to determine what it'll suggest to you.
Am I wrong in my assumption? And is there any way to have type-hinting that won't trip on itself when using external modules with, sometimes, classes having the same name as each other?
I tried your code in Visual Studio:
geom/Rectangle.ts
class Rectangle {
calculateSurface() {
console.log("a");
}
}
export = Rectangle;
ui/Rectangle.ts
class Rectangle {
display() {
console.log("b");
}
}
export = Rectangle;
Test.ts
import GeomRectangle = require("./geom/Rectangle");
import UiRectangle = require("./ui/Rectangle");
var x: GeomRectangle = new GeomRectangle();
var ui: UiRectangle = new UiRectangle();
// Now both those are valid
ui.calculateSurface(); // compilation error here
ui.display();
There is no calculateSurface method in the intellisense options of the ui object.
There is compilation error on the ui.calculateSurface() line
So it probably could be bug related to Intellij IDEA or configuration issue.
I've read many recommendations of how it's possible to render routed via react-router components, but I still can't to make it work. I tried to find it using github codebase search, still no luck. And at this point all I need is one working example.
Here is my boilerplate project, but maybe it's not important. I just want to see some react-route unit-testing working example.
I got mine working after I found the super-secret hidden react-router testing guide.
Instead of using Object.assign to create a router stub, I used sinon.js so I could create better stub functions that return the appropriate values for my tests.
EDIT: Went back to look again at your boilerplate and saw that your stub router is borrowed from the same example. Sorry. So where exactly did you get stuck?
EDIT-AGAIN: I'm not using Jest, so here are the other pieces that I needed to solve the testing puzzle:
If you're using browserify, and want to test in plain mocha (without having to build), you'll need to hack require to compile your jsx for you:
var fs = require("fs");
var reactTools = require("react-tools");
require.extensions[".jsx"] = function(module, filename) {
var jsxContent = fs.readFileSync(filename).toString();
var jsContent = reactTools.transform(jsxContent);
return module._compile(jsContent, filename);
};
You need a fake DOM. JSDOM is just plain terrible. I got it working using domino instead.
var domino = require("domino");
global.window = domino.createWindow();
global.document = global.window.document;
//Set the NODE_ENV so we can call `render`.
//Otherwise we get an error from react about server rendering. :(
process.env.NODE_ENV = "test";
Then you can require your components in through the stub-router, and render your components into DOM nodes using React.render():
var MyComponent = fakeRouter(require("./MyComponent.jsx"));
var component = React.render(
< MyComponent / > ,
document.body
);
node = component.getDOMNode();
//I used `zepto-node` and `chai-jq` to assert against my components
The (possbily new in v4) way of doing this is to wrap the component you're testing in the MemoryRouter provided by react-router.
import {MemoryRouter} from 'react-router-dom';
import {render} from 'react-dom';
render(<MemoryRouter>
<YourComponent>
</MemoryRouter>, node, () => {});