I have a plain class (meaning it doesn't extend from React.Component), and I want to go to a new route):
class CalculatorService {
constructor() {
}
sum(a, b){ return a+b; }
minus(a, b){ return a-b; }
goSomeWhere(){ GO TO HOME PAGE. What do I put here? }
}
export default CalculatorService;
Of course I import this class into React components and use its functions from there, and when I execute goSomeWhere it should go to a different page, even though this class is a logic class and has nothing to do with React.
My solutions so far is to use a library called react-navigation to no avail because I didn't understand it. I also tried passing a function into the constructor so it could call some Component's method where navigation is possible. But none of these worked.
The idea isn't to call the route change within the CalculatorService class but getting the callback or return response from the class to be notified of the moment when you would like to change the route (of course you don't necessarily have to be 'notified' if all your codes are synchronous) and making the route change in the React component.
As to programmatically changing the route, do refer to my another answer Stateless component React router
Related
Im really new to react and react-native and having problem with this really simple code below.
The code below is on a minimal react native app.
It renders the content inside the render method but looks dont executing the instructions inside the constructor, i havent the alert box neither the log appears in console.
I need ensure a variable is initialized just on application startup and it was my way to check it, im thinking about use a logic using Undefined and give up on using contructor.
Some related links i found:
constructor in React not being called upon component being instantiated
Console.Log Not Being Called Inside React Constructor
My code :
class TestComponent extends Component {
Constructor(props){
this.super(props);
console.log("CalingConstructorLog"); // do nothing
Alert.alert("CalingConstructorLog"); // do nothing
}
render() {
return (
<Text>It renders OK!</Text>
);
}
}
export default TestComponent;
When using React, what is the difference (and when should each method be applied) when rendering a component?
Does this impact the component lifecycle in any way? Or impact how hooks are run in the component?
Method 1:
class App extends React.Component {
...
function getComponent() {
return <Component />
}
render() {
return this.getComponent()
}
}
Method 2:
class App extends React.Component {
...
render() {
return <Component />
}
}
(Note: The OP has now changed the question, it used to have return {this.getComponent()} in Method 1.)
render in Method 1 is incorrect (well, it was before the edit), it should be:
render() {
return this.getComponent() // No {} wrapper
}
You need the {} within a JSX context, but you're not in a JSX context there. For instance, if you wanted to wrap what this.getComponent returned in a div, you'd use the JSX expression to define the div's children within the JSX defining the div:
render() {
return <div>{this.getComponent()}</div>
}
With the {} sorted out, whether you use Method 1 or Method 2 is up to you. If you have substantial parts of the render that you want to move into their own functions, that's fine. For instance:
render() {
return (
<div>
{this.getHeader()}
{this.getBody()}
{this.getFooter()}
</div>
);
}
...although I think I'd probably argue at that point that without a good counter-argument, the header, body, and footer should probably be components (perhaps function components). But the occasional helper function call like that is fine.
Does this impact the component lifecycle in anyway?
No. It's just a function call within render.
There is no real difference between both. I'd personally use only one render() method as much as possible, then when the method gets too big, extract parts of it into their own method.
I have found this great article by Kent C. Dodds. An extract of the article is:
React doesn't know the difference between us calling a function in our JSX and inlining it. So it cannot associate anything to the Counter function, because it's not being rendered like a component.
This is why you need to use JSX (or React.createElement) when rendering components rather than simply calling the function. That way, any hooks that are used can be registered with the instance of the component that React creates.
With this in mind, it sounds like it's better to use JSX when rendering a component that uses hooks.
First, some context.
I'm using Redux to manage authentication state of my app and have Auth as a Redux container (or smart component).
I've created a wrapper (a higher-order component) that takes Auth and returns it:
export default function AuthWrapper(WrappedComponent) {
class Auth extends Component {
... <Auth stuff here> ...
}
return connect(mapStateToProps, mapDispatchToProps)(Auth);
}
It seems to me that in order to use the wrapper, I just need to invoke it with a component I want to have behind my auth. For example, let's say I'm authenticating a component called UserPage with the wrapper, à la:
const AuthenticatedUserPage = AuthWappper(UserPage)
However, when I use the wrapper like this, React isn't happy with me. I get the following error:
Warning: AuthenticatedApp(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
My best guess is that it doesn't like the connect-ified component that Redux will create when I return it from AuthWrapper... which leads me to my question:
Does React support higher-order components when those components create Redux containers? And if so, why would React be throwing this error?
Here's my two cents. I think the error is occurring elsewhere.
According to this simplified version of the connect function in react-redux, the connect function is simply returning another react component. So in your case, you're returning a component, wrapped inside another component, which is still valid. A container is basically a component.
Read https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e for a better understanding of the connect function.
I also tried the following in my own application and it worked.
import Layout from '../components/Layout'
//Do some other imports and stuff
function wrapper(Layout) {
return connect(null, mapDispatchToProps)(Layout);
}
export default wrapper()
Like the error states, you might just simply be returning an invalid component somewhere in your app. Your app might be throwing the error because you're not wrapping a return call in parentheses on your render method.
According to the react documentation: http://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount we are adviced use componentDidMount for AJAX call that should be issued when a component is brought into view.
However, when switching between to instances of the same component with different props, componentDidMount is only called for the first component. So what are we supposed to do in this situation?
Currently I have the following workaround: In componentDidMount i do my AJAX call and In componentDidUpdate I compare old and new props to check if I am on a new "instance", and if so I do my AJAX call. But that seems exactly like a workaround. So my question is: is this really the way to do it?
I am aware that I could wrap my component in different empty components to solve my problem. However, this is not possible because we are building a data driven application that uses configurable components and it makes sense to use the same component with different configurations - which is where I'm running into problems.
I am aware that we are actually talking about react elements and not instances as such - witch I guess is part of the problem. Probably I have different react elements utilizing the same instance.
I have made a tiny example to illustrate the react behavior, using plain react (just to make sure I wasn't tricked by react-router or redux and what else we are using the real app):
class Foo extends React.Component {
componentDidMount() {
console.log('componentDidMount ' + this.props.foo);
}
componentDidUpdate() {
console.log('componentDidUpdate ' + this.props.foo);
}
render() {
return <div>Route is {this.props.foo}</div>;
}
}
function navigated() {
ReactDOM.render(
<Foo foo={window.location.hash} />,
document.getElementById('app')
);
}
window.addEventListener('hashchange', navigated, false);
navigated();
Initially when I go to #/bar I get 'componentDidMount #/bar' and when I go to #/baz i get 'componentDidUpdate #/baz'.
I seems like this unanswered question is a specific case of the same issue: React does not know when i render the same component
You can add the key property with unique value for each of hashes:
ReactDOM.render(
<Component hash={hash} key={hash} />, domNode
);
This will update the component every time when the hash is really changed.
https://facebook.github.io/react/docs/multiple-components.html#dynamic-children
TL DR - your 'workaround' looks correct to me
When you initially render the component componentDidMount is called, when you change the hash prop componentDidUpdate is called. It is still the same component, it is just that a specific prop has changed value. In your case, you have logic (running an AJAX call when hash changes) that is specific to your application. React does not known that the hash prop is special, you make is special by adding the logic in componentDidMount. So I believe you have a good interpretation of the React docs and this way of achieving your goal is perfectly valid.
Let's say that I create additional functions in my React components, something like this:
class Cart extends React.Component {
render() {
return <div id="cart">My Cart Items</div>
}
getItem(id) {
// magically return the item
}
addItem(id, name, type, price){
// you get the idea
}
}
Now, what is the best way to access getItem function from outside the class? For example, something that can be used as window.Cart.getItem. It seems to me that these functions are part of the prototype (non-initialized) of nodeName property of what ReactDOM.render returns.
What is the correct way for this? Thanks.
That's not really how react is supposed to be used.
What you are trying to do looks like MVC, and react is a completely different thing.
a React component like your <Cart> receives props from its parent (could be the root reactDOM.render() or another react component)
a React component may have internal and private method to retrieve additional data from elsewhere (but NOT from other react components)
with these inputs (and only these inputs), the component knows what and how to render itself and possibly also children components to the DOM
the stuff the component (or its children components) render may include interaction handlers (e.g. remove from cart button like `
these interactions could fire an internal method inside the component
and the internal method could call a method in a parent component, if it was passed down as a prop.
or call some remote function to remove item from cart on server side.
In react terms, the <Cart> component is not the owner of the cart contents. It gets them as props, or retrieves them from somewhere else.
React really wants you to ONLY update the cart by passing a new set of props to the component to render.
You could try to shortcut react design by trying to expose any methods from the component to the outside world, but this goes against react design principles.
React has a one way data flow: a component gets props, and renders.
For reference, I can recommend this page on react principles.
You can make a reference to the instance :)
<Cart ref={function(instance){ window.CartInstance = instance }} />
window.CartInstance.getItem(foo);
ES6
<Cart ref={(instance)=>window.CartInstance = instance} />
window.CartInstance.getItem(foo);