react how to call state variable from another class? - javascript

Search.js
class Search extends Component {
constructor() {
super();
this.state = {
selectedPictures: []
}
}
static getSelectedPictures = () => {
return this.state.selectedPictures;
}
render() {
return (
<div>
...
</div>
);
}
}
export default Search;
Other.js
import Search from './Search';
class Other extends Component {
constructor() {
super();
this.state = {
}
}
render() {
console.log(Search.getSelectedPictures); --> Uncaught null
return (
<div>
...
</div>
);
}
}
export default Other;
How to call Search.state.selectedPictures inside Other.js?
I already try to use static method to return this.state.selectedPictures and call in Other.js, but cannot access.
Any way can import or transfer the var? Both js files are separate files
Thank you.

What you're trying to do isn't really possible in React for a couple of reasons. First of all, you're trying to call methods and access properties on a class, not on an object. You would, in normal (modern) JS, be required to instantiate the class with the new keyword. For example, search = new Search(); search.getSelectedPictures() - this, however, isn't really how React works, and because your classes are actually components, you have to use the <Search/> component syntax in your render function.
As for getting access to the state in Search, you'd need to pass that state from Search to Other.
One way would be to pass the state into the props directly, so in search.js:
render() {
<Other selectedPictures={this.state.selectedPictures} />
}
Then in other.js:
render() {
this.props.selectedPicture.forEach((pic) => <img src={pic} />);
}
Alternatively, you could have a more umbrella parent component, and keep the state in there. Then pass that state to both components simultaneously, if the ones you list are not meant to have a parent-child relationship.
There are also, albeit slightly more complex, ways of doing what you wish but with Search as a child of Other, but without knowing what those two components actually are, it's hard to really tell.

Use flux architecture . The simple implementation is
alt flux
Just create an Action and a Store . When you select images just put them in the Store using Action then get them as props using <AltContainer />

Related

Passing props from one class component to other in react js

I am taking a beginner's course on react js. I came across class components and I wanted to know how does the props object get initialized.
for eg:
Main Component:
class App extends React.Component {
render() {
return (
<div>
<Header username="xyz"/>
</div>
)
}
}
Header:
class Header extends React.Component {
render() {
return (
<div>
<p>Welcome, {this.props.username}</p>
</div>
)
}
}
I wanted to know does the props object in Header class is getting initialized?
Shouldn't it be something like this:
class Header extends React.Component {
constructor(props) {
super()
this.props = props
}
render() {
return (
<div>
<p>Welcome, {this.props.username}</p>
</div>
)
}
}
By using the above code I am a getting a message:
ReferenceError: Must call super constructor in derived class before
accessing 'this' or returning from derived constructor
My question is, if we want to pass anything to a class, shouldn't it be done using a constructor?
By extending React.Component, React does this for you.
The props object should never be changed inside the receiving component. React class components will gather all the arguments you pass to a component, and refer to them by the common name "props". This is why you don't have to do it yourself, in the constructor.
However, in modern React, class components are rarely used. The reason is that class components easily ends up with complicated lifecycle management.
The Header component, written as a function rather than a class, would look like this:
const Header = (props) => (
<div>
<p>Welcome, {props.username}</p>
</div>
)
It is also very common to destructure props directly, so that you never really access the props object, like this:
const Header = ({username}) => (
<div>
<p>Welcome, {username}</p>
</div>
)
In the case of function components, you're free to use whatever name you want for the props. I wouldn't do it though, because people are used to props being called props. But this would work as well:
const Header = (params) => (
<div>
<p>Welcome, {params.username}</p>
</div>
)
I used the same code as you post without constructor and I don't have any error.
You can pass what you want to a class without using a constructor like you did in your example code.
I share the link of your code in sandbox.
I put the constructor in Header to show that it returns the same with it and without it.

React context props drilling, what is it that I don't get?

There is a TL;DR at the bottom.
I am probably doing this wrong or using the context in an bad way. I am new to react so I have no clue if this is how we are meant to do things.
My understanding:
Context can be used to pass down props to deeper nested child components without having to pass them through all levels of nesting. A provider is filled with props, and a consumer will look "up the tree" to find the nearest provider and get it's data.
If this is the case, then I can load a provider with a function, such as an onChange handler in order to avoid having to write the handler on every child component when they all do the same thing. This would allow for a "smart form" which govern's its input's handlers by "passing" handlers given to it. Obviously just writing one handler on multiple components is not an issue, but having like 20-30 form fields and writing 4+ handlers on each of them just creates code clutter. So I tried the following:
HTML structure is like this, for example:
<ControlledForm data={some_data} handlers={some_handlers}>
<LabeledControl name="Type your name" rel="Name" meta={{some_meta_object}}></LabeledControl>
<LabeledControl name="Pet name" rel="PetName" meta={{some_meta_object}}></LabeledControl>
<LabeledControl name="Type of pet" rel="PetType" meta={{some_meta_object}}></LabeledControl>
<LabeledControl name="Family" rel="Family" meta={{some_meta_object}}></LabeledControl>
</ControlledForm>
And this is the ControlledForm class code:
const { Provider } = React.createContext(); //Note this
class ControlledForm extends Component {
state = {};
render() {
return (
<Provider value={{ onChange: this.props.onChange }}>
<form>{this.props.children}</form>
</Provider>
);
}
}
Now whatever child I place within this form would want to have a <Consumer> wrapper around it to consume the changeHandler, or at least this is the plan. However when I wrap my LabeledControl in a consumer, it acts as if it has no data.
<LabeledControl> (reduced code):
const { Consumer } = React.createContext();
class LabeledControl extends Component {
state = {};
render() {
return (
<Consumer>
{r => {
console.log("consumer:", r); //Logs undefined
return (
<div className="labeled-control">
{/*Code here*/}
</div>
);
}}
</Consumer>
);
}
}
If I was to guess at what the issue is, I'd say it is because both the ControlledForm and the LabeledControl create it's own context, which is not shared, look at the code above. But I do not understand how would I share this context and still keep the two classes in separate .js files. I cannot pass a reference down to the children, all I get is the {this.props.children} and no way to tell it "Hey use this provider here". All the examples I find online have the two classes that are a provider and a consumer in a same file, being able to reference the same "context" but this seriously impacts the freedom of what I can put inside a form, or rather doesn't let me have customization in terms of "children".
TLDR
How do I pass down a "Context" from a Provider to a Consumer when they are in two different javascript files? Code is above. I essentially need to pass down a handler to every child and have it (maybe, maybe not, depending on a child) use the handler to tell the parent to update it's data. All of this whilst using {this.props.children} in a parent in order to allow "outter code" to "inject" the parent component with any children desired and have them either use or not use the parent's handler.
Edit:
I searched about a bit and found two possible solutions, which I both tested and both seem to be working (with a limited use case). Both render props and React.CloneElement seem to do the trick when there is one level of nesting as we can directly render and add props to children with them, but when we need to prop drill several levels, all the components in between would have to implement the same passing of props which then turns to spaghetti code. Still searching to try and find the way to pass the context down to the children for consumption in different files.
Please view the code below.
Also: here is a sample project I have built:https://codesandbox.io/s/5z62q8qnox
import React from 'react'
import PropTypes from 'prop-types';
import 'bootstrap/dist/css/bootstrap.min.css';
export default class ControllerForm extends React.Component {
static childContextTypes = {
onChange: PropTypes.func.isRequired
}
getChildContext() {
return {
onChange: this.handleOnChange
}
}
handleOnChange = (e) => {
console.log(e.target.value) //here is the place you have to implement
}
render() {
return (
<div class="container">
{this.props.children}
</div>
)
}
}
import React from 'react'
import PropTypes from 'prop-types';
import 'bootstrap/dist/css/bootstrap.min.css';
export default class LabeledControl extends React.Component {
static contextTypes ={
onChange : PropTypes.func.isRequired
}
render() {
return (
<div>
<div className="form-group">
<input className="form-control" type="text" onChange={this.context.onChange} />
</div>
</div>
)
}
}
function App() {
return (
<div className="App">
<ControllerForm>
<LabeledControl />
<LabeledControl />
</ControllerForm>
</div>
);
}
It appears that Context is not what I should be using for this, instead either render props or React.cloneElement() is the proper solution, despite my best efforts to enforce a context.
Parent's render:
{this.props.children.map((child, index) =>
React.cloneElement(child, { key: index, handler: handler })
)}
Child's render:
return (
<div>
<span onClick={this.props.handler}>{passed.foo}</span>
</div>
);
This way the structure remains clean and handlers get passed down. Only issue is every component that needs to pass them down has to implement this, but it would have been the same with context, since it is not exported to a separate file.

Storing methods needed in all components

I have a universal app I'm developing for learning purposes. I'm managing the state of my app with Redux, so all my data will be available there. But I want to create some methods that I'm going to use in all my components. The problem is: where should I store this methods?
Adding them to a parent component and passing the methods as props doesn't seem very useful, because this is one of the things that Redux tries to solve. And I'm pretty sure that Redux is not a place for storing methods.
I know I can create a class in a file somewhere, export it, add some methods to it, and when I want to use one method in a component I can call this file, create an instance of the class and call the needed method; but this doesn't look very react to me…
Is there a right way to create methods available for all components?
I've had some success sharing functions between components using an approach similar to the following. I'm not sure this approach will solve your specific use case with regards to cookies, however.
These functions can be stored anywhere and imported wherever required. They accept a component as their first argument, then return a function that operates on the component passed in.
Indicative, untested code follows.
// An event handler than can be shared between multiple components
const handleChange = component => event => component.setState({ value: event.target.value });
class ComponentOne extends PureComponent {
state = {};
render() {
return (
<div>
{this.state.value}
<input onChange={handleChange(this)} />
</div>
);
}
}
class ComponentTwo extends PureComponent {
state = {};
render() {
return (
<div>
{this.state.value}
<input onChange={handleChange(this)} />
</div>
);
}
}

writing function outside of a class in react component

I've seen code like this
function abc(){
return 'abc'
}
class MyComponent extends React.Component {
static abc = abc;
render() { return <h1>{this.abc}</h1>; }
}
where function abc is defined outside of a react class. I have no clue why the author did it that way, why can't just do it within the class?
These are ES6 static methods and are not exclusive to React. They are members of the component class and not of instances of the component. They are not used extensively in React, but they can be useful. It is even mentioned in the React docs:
Sometimes it’s useful to define a static method on a React component.
For example, Relay containers expose a static method getFragment to
facilitate the composition of GraphQL fragments.
They can be used as common members of the Component, shared by all instances of it. To give you an idea, other static members of a React class are displayName and defaultProps.
Also see Static methods in React. As you can see, there aren't many cases where you would use a static method.
For one thing declaring functions outside the class are easier to EXPORT. Which serves a great deal when testing your react application i.e. through jest.
import React, { Component } from 'react';
class Contacts extends Component {
render() {
return (
Contact()
);
}
}
const Contact = () => {
return (
<div>
<p>Contactssssss</p>
</div>
);
};
export default Contacts;

React - How to access props without using constructor

Note: I encounter this specific problem using React Native, but I guess this goes for React in general as well.
I have a react component built using React.Component.
I don't need to set state, but I do have props. My proposed syntax was as follows:
class Header extends Component {
constructor(props) {
super(props);
}
render() {
return <div>{this.props.title}</div>;
}
}
I understand I can use a function to construct this component, like this:
const Header = (props) => {
return <div>{props.title}</div>;
}
But I prefer the former, because my component will grow, might have state etc, and I just want to keep all my components built in a similar fashion.
Now, my linter complains about having a useless constructor, but how else do I access the props while keeping a class constructor instead of a function constructor?
If you want to use this.props in the constructor, you need to pass props to super. Otherwise, it doesn't matter because React sets .props on the instance from the outside immediately after calling the constructor.
So just simply remove constructor() if useless
you can access props without constructor in a class using "this", like this:
class XXXXXX extends React.Component {
render() {
return (
<div>{this.props.value}</div>
)
}
}

Categories

Resources