React exporting multiple method calling another method error - javascript

Currently i am exporting only one funtin like this and it works great
import React from "react";
import SocialLogin from "from somewwhere";
class GoogleButton extends React.Component {
render() {
const { fontClass, triggerLogin, ...props } = this.props;
return (
<div className="">
Google
</div>
);
}
}
export default SocialLogin(GoogleButton);
But when I try to export multiple functions, it doesn't work.
import React from "react";
import SocialLogin from "from somewhere";
class GoogleButton extends React.Component {
render() {
const { fontClass, triggerLogin, ...props } = this.props;
return (
<div className="">
Google
</div>
);
}
}
class FacebookButton extends React.Component {
render() {
const { fontClass, triggerLogin, ...props } = this.props;
return (
<div className="">
Facebook
</div>
);
}
}
export {
SocialLogin(GoogleButton),
SocialLogin(FacebookButton);
}
Can anyone tell me why it doesnt work? It works when i do like this
export {
SomeFunc,
AnotherFun,
}
But what's wrong with it if i put it inside a functin? Can anyone tell me how can i do it?

You cam simply do this.
import React from "react";
import SocialLogin from "from somewhere";
export class GoogleButton extends React.Component {
render() {
const { fontClass, triggerLogin, ...props } = this.props;
return (
<div className="">
Google
</div>
);
}
}
export class FacebookButton extends React.Component {
render() {
const { fontClass, triggerLogin, ...props } = this.props;
return (
<div className="">
Facebook
</div>
);
}
}
Or you can do this.
.... Existing components
export default {
SocialLoginGoogle: SocialLogin(GoogleButton),
SocialLoginFacebook: SocialLogin(FacebookButton)
}
The below one works as it is considering object's key and value has the same name. Hence, shorthand.
export {
SomeFunc,
AnotherFun,
}

Related

Why newly dynamically added Card components doesn't re render on form submit

I am trying to fetch data from GitHub user API and store the JSON in an array, and then and then loop through the array and create Card components dynamically on submission of form, but the Card components doesn't render even though the array is updated with the newly added user.
I have added relevant code files and image of React component tree on dev console before and after valid form submission. Thanks.
App.js
import React from "react";
import Form from "./Form";
import Cardlist from "./Cardlist";
import ProfileData from "../JSON";
export default class App extends React.Component {
testData = ProfileData();
state = {
profiles: this.testData,
};
addNewProfile = (profile) => {
this.setState({
profiles: [...this.state.profiles, profile],
});
};
render() {
return (
<div>
<h4>GITHUB PROFILE CARDS</h4>
<Form onSubmit={this.addNewProfile} />
<Cardlist profiles={this.state.profiles} />
</div>
);
}
}
Form.js
import React from "react";
export default class Form extends React.Component {
state = { userName: "" };
handleSubmit = (event) => (
event.preventDefault(),
fetch(`https://api.github.com/users/${this.state.userName}`)
.then((response) => {
return response.json();
})
.then((data) => {
this.props.onSubmit(data);
})
);
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
type="text"
placeholder="username"
value={this.state.userName}
onChange={(event) =>
this.setState({ userName: event.target.value })
}
/>
<button>Add Card</button>
</form>
</div>
);
}
}
Cardlist.js
import React from "react";
import Card from "./Card";
export default class Cardlist extends React.Component {
profile = this.props.profiles.map((element) => (
<Card key={element.id} {...element} />
));
render() {
return (<div>{this.profile}</div>);
}
}
Card.js
import React from "react";
export default class Card extends React.Component {
render() {
return(
<div style = {{display: 'flex'}}>
<img src = {this.props.avatar_url} style = {{width: '100px', height: '100px'}}/>
<div>
<h6>{this.props.name}</h6>
<h6>{this.props.name}</h6>
</div>
</div>
);
}
}
component tree before
array before
component tree after
array after
You can change your CardList component to:
import React from "react";
import Card from "./Card";
export default class Cardlist extends React.Component {
render() {
return (
this.props.profiles.map((element) => (
<Card key={element.id} {...element} />
))
);
}
}
The problem with your CardList component is that you have a class property (profile) which is initialized when the CardList component is created but the class property does not update its value when the props is updated.
PS: you can also convert your class property into a function
profile = () => (
this.props.profiles.map((element) => (
<Card key={element.id} {...element} />
))
);
and the on render
render() {
return (<div>{this.profile()}</div>);
}
In Cardlist.js, instead of using a class variable, directly return the mapped elements.
import React from "react";
import Card from "./Card";
export default class Cardlist extends React.Component {
render() {
return this.props.profiles.map((element) => (
<Card key={element.id} {...element} />
));
}
}
Working demo on Codesandbox.
Although your CardList is received a new props from parent and then get rerender, this.profile outside your render function, so it never get updated. Just put it inside your render function and it works fine
class Cardlist extends React.Component {
render() {
const profile = this.props.profiles.map((element) => (
<Card key={element.id} {...element} />
));
return <div>{profile}</div>;
}
}
codesanbox

How to share data between react classes?

How can I share the data value that I have from the handleClick function inside the Module class to the InputSelect class, all the classes are in the same file?? I'm not using Redux.
I can't use props because there is not a relationship between these classes..
Should I nest all the classes??
Any suggestion??
import React, { useState } from "react";
const array = [ ];
class InputSelect extends React.Component {
render() {
return (
<div>
{ 'Put it here........' }
</div>
)
}
}
class Module extends React.Component {
handleClick(e) {
console.log(e.currentTarget.textContent);
}
render() {
return (
<div
onClick={this.handleClick}
>
{this.props.id}
</div>
);
}
}
function App() {
return (
<div>
<Menu availableModules={array} />
</div>
);
}
export default App;
Correctly stated by #Federkun above, you should use React context.
Check the react docs here

Update state for component by event handle in other component in different file?

I have two component in my project one is Tag and the other is LandingTicker so i want when i click Tag componet update state for LandTicker componet, and landticker componet in different file.
how i can do that?
thank you.
Tag component code::
tag/index.js
import React from 'react';
import './index.scss';
class Tag extends React.Component {
handleClick(e) {
let tags = document.querySelectorAll('.show-clickable');
Array.from(tags).map(el => el.classList.remove('selected-tag'))
e.target.classList.add('selected-tag');
/*
Here i should update the state for LandingTicker component.
and remember any component in different file.
How i can do that???
*/
}
render() {
return (
<div
className="show-clickable"
onClick={this.handleClick}
>
click here
</div>
);
}
}
export default Tag;
LandingTicker component code::
LandingTicker/index.js
import React from 'react';
import TickerRow from './TickerRow';
import './index.scss';
class LandingTicker extends React.Component {
state = {
coin: 'USD'
}
render() {
return (
<div className="landing-ticker__body">
{selectCoin(this.state.coin)}
</div>
</div>
);
}
}
const selectCoin = (coin) => {
const coins = {
USD: ['BTCUSD', 'ETHUSD', 'EOSUSD', 'LTCUSD'],
EUR: ['BTCEUR', 'ETHEUR', 'EOSEUR'],
GBP: ['BTCGBP', 'EOSGBP'],
JPY: ['BTCJPY', 'ETHJPY'],
};
return (
coins[coin].map(el =>
<TickerRow symbol={el} key={el.toString()} />
)
);
}
export default LandingTicker;
Edit:
my component Hierarchy::
StatusTable
TagsTable
Tag
TickerSearch
LandingTickers
TickersRow
StatusTable component code::
import React from 'react';
import TagsTable from './TagsTable';
import TickerSearch from './TickerSearch';
import LandingTicker from './LandingTicker';
import './StatusTable.scss';
class StatusTable extends React.Component {
render() {
return (
<div className="status-table">
<TagsTable />
<TickerSearch />
<LandingTicker />
</div>
);
}
}
export default StatusTable;
React handle all its component data in the form of state and props(immutable). So it is easy to pass data from parent to child or one component to another using props :
Your Tag.js file:
import React, { Component } from "react";
import LandingTicker from "./LandTicker";
class Tag extends Component {
constructor(props) {
super(props);
this.state = {
trigger: true
};
}
handleClick(e) {
// do all logic here and set state here
this.setState({ trigger: this.state.trigger });
}
render() {
//And then pass this state here as a props
return (
<div className="show-clickable" onClick={this.handleClick}>
click here
<LandingTicker trigger={this.state.trigger} />
</div>
);
}
}
export default Tag;
Inside LandTicker.js file:
import React from 'react';
import TickerRow from './TickerRow';
import './index.scss';
class LandingTicker extends React.Component {
state = {
coin: 'USD'
}
render() {
//Catch your props from parent here
//i.e this.props(it contains all data you sent from parent)
return (
<div className="landing-ticker__body">
{selectCoin(this.state.coin)}
</div>
);
}
}
const selectCoin = (coin) => {
const coins = {
USD: ['BTCUSD', 'ETHUSD', 'EOSUSD', 'LTCUSD'],
EUR: ['BTCEUR', 'ETHEUR', 'EOSEUR'],
GBP: ['BTCGBP', 'EOSGBP'],
JPY: ['BTCJPY', 'ETHJPY'],
};
return (
coins[coin].map(el =>
<TickerRow symbol={el} key={el.toString()} />
)
);
}
export default LandingTicker;
I think this is the best answer for your question if you don't use state management system such as Redux or Mobx.
https://medium.com/#ruthmpardee/passing-data-between-react-components-103ad82ebd17
(you need to check third option)

React data do not go to child component after fetch

I'm having a problem with the function fetch. I'm trying to send just a number for example "1", and I have access to this data in all child components, but after calling fetch, I'm no longer able to access this data.
App.jsx:
import React, { Component } from 'react'
import './App.css';
import fetch from 'isomorphic-fetch'
import Header from './Header'
import Content from './Content'
import Footer from './Footer'
class App extends Component {
constructor(props) {
super(props)
this.state = {
stripdata: null
}
}
componentWillMount() {
fetch(`http://localhost:3000/data/info.json`)
.then(results => results.json())
.then(data => {
this.setState({
stripdata: data
})
// console.log(this.state.stripdata)
})
.catch(err => {
console.log("Didn't connect to API", err)
})
}
render() {
// console.log(this.state.stripdata)
return (
<div className="App">
<Header onQuery={1}/>
{
(this.state.data === null) ? <div className="loading">Loading data...</div> : <Content onResult={this.state.stripdata}/>
}
<Footer />
</div>
);
}
}
export default App;
Content.jsx:
import React, { Component } from 'react'
import Result from './Result'
class Content extends Component {
constructor(props) {
super(props);
this.state = {
stripdata: this.props.onResult
};
}
componentWillMount() {
}
render() {
console.log("im an Content: " + this.state.stripdata)
return (
<div className="Content">
<Result stripdata={ this.state.stripdata }/>
</div>
);
}
}
export default Content;
Result.jsx:
import React, { Component } from 'react'
import PersonCard from './PersonCard'
class Result extends Component {
constructor(props) {
super(props);
this.state = {
stripdata: this.props.stripdata
};
}
componentWillMount() {
}
render() {
console.log("im the Result: " + this.state.stripdata)
return (
<div className="result">
<PersonCard />
</div>
);
}
}
export default Result;
Please help. This is blocking my progress.
Fix the issue here:
<Header onQuery={1}/>
{
(this.state.stripdata === null) ? <div className="loading">Loading data...</div> : <Content onResult={this.state.stripdata}/>
}
You need to check properties in state with name stripdata.
And btw, fetch has to be performed in ComponentDidMount, see https://daveceddia.com/where-fetch-data-componentwillmount-vs-componentdidmount/
The problem is that, in your Results, you are only using the value from props once: in the constructor, where you set to state.
You should not set value in state from props. Instead, just use the props directly. Change Result to as following, then it will work proper:
import React, { Component } from 'react'
import PersonCard from './PersonCard'
class Result extends Component {
constructor(props) {
super(props);
// removed setting state from props.stripdata
}
render() {
console.log("im the Result: " + this.props.stripdata) // <-- using props!
return (
<div className="result">
<PersonCard />
</div>
);
}
}
export default Result;
In general it is considered bad practice/antipattern to set state from props.

React: Render other blocks

I'm new to reactjs, I'm trying to communicate 2 component and render again one of them.
I have the following:
layout.js
import React from 'react';
...
class Layout extends React.Component {
constructor(props) {
super(props);
this.state = {
toolbar: 'none'
};
}
getChildContext() {
let me = this;
return {
changeToolbar: function (newToolbar) {
me.setState({ toolbar: newToolbar })
}
}
}
render() {
const {Search, Nav} = this.props;
return (
<div className="wrap">
<Header Search={Search} />
<Toolbar toolbar={this.state.toolbar} />
<div className="main">
<Nav />
<div className="content">
{this.props.children}
</div>
</div>
</div>
)
}
}
Layout.childContextTypes = {
changeToolbar: React.PropTypes.func
}
export default Layout;
toolbar.js
import React from 'react';
...
import ProductToolbar from '../components/toolbar/productToolbar';
import SalesToolbar from '../components/toolbar/salesToolbar';
class Toolbar extends React.Component {
static propTypes = {
toolbar: React.PropTypes.string.isRequired
};
state = {
toolbar: this.props.toolbar
};
componentWillReceiveProps(next_props) {
this.setState({toolbar: next_props.toolbar})
}
render () {
let bar = <div>{this.state.toolbar} undefined</div>;
switch (this.state.toolbar) {
case 'productToolbar':
bar = ProductToolbar;
break;
case 'salesToolbar':
bar = SalesToolbar;
break;
};
return (
<div className='toolbar show'>
{bar}
</div>
)
}
}
export default Toolbar;
productToolbar.js
import React from 'react';
export default class ProductToolbar extends React.Component {
render() {
return (
<div>
productToolbar
</div>
);
}
};
productPage.js
import React, {Component} from 'react';
...
class ProductPage extends React.Component {
componentDidMount() {
this.context.changeToolbar('productToolbar');
};
render() {
return (
<div>Page</div>
);
}
};
ComisionPage.contextTypes = {
changeToolbar: React.PropTypes.func
}
export default ProductPage;
when desire is loaded productPage.js create a special toolbar with options for Productpage.
I pass the name of the toolbar to render the new view, but it does not, missing or that I'm doing wrong?
another best solution was to pass directly toolbar
productPage.js
import ProductToolbar from '../components/toolbar/productToolbar';
...
componentDidMount() {
this.context.changeToolbar(ProductToolbar);
};
It not works for me
Just to make sure that you are rendering the element. Can you please change you switch statement to:
switch (this.state.toolbar) {
case 'productToolbar':
bar = <ProductToolbar />;
break;
case 'salesToolbar':
bar = <SalesToolbar />;
break;
};
Also, consider using a store (Redux, AltJs?) instead of context since they can get a bit complex on large apps (...I experienced the pain, until I switch to the 'store' approach)

Categories