Use multiple components in react - javascript

I am new to reactjs and I'm creating a project using it. I have a problem while using multiple components. Here is the scenario
when the page is loaded both component is loaded values of type,getcpeyearlysval and getvnfyearlysval are set
setDataMeter1(){
//here i want only type cpe componnet will load
}
<Speedometer type = "cpe" getcpeyearlysval={this.objSpeedometer.getcpeyearlys}/>
<Speedometer type = "vnf" getvnfyearlysval={this.objSpeedometer.getvnfyearlys}/>
Now I want when I to call this.setDataMeter1 function only type cpe component should work, but the problem is both calls.
<select value={this.state.selectValue} onChange={this.setDataMeter1}>
In Speedometer component:
renderIcon(key, val) {
if(key == 'vnf') {
console.log("vnf")
}
if(key == 'cpe'){
console.log("cpe")// this condition should met
}
}
render() {
return (
this.renderIcon(this.props.type, this.props)
);
}
}
But my problem is both conditions mets in speedometer components.

renderIcon(props) {
if(props.type == 'vnf') {
return <Text>hey this is vnf </Text>
}
if(props.type == 'cpe'){
return <Text>hey this is cpe </Text>
}
}
render() {
return (
this.renderIcon(this.props)
);
}

Related

How to setTimout on react component

I have a component which fetch data from backend. Here I have already added loading while the component fetch on data from backend. But the problem is if there is no data available there it still keeps on showing that loading. Instead I want to show something like There is nothing In here Text on screen if loading is complete and no data is available there. I want to know how to implement this any help would be great.
This is my code
class FootStep extends React.Component {
componentDidMount() {
this.props.getFootstep();
}
render() {
const { loaded, loading, error, data } = this.props.footstep.data;
console.log("footstepContainer props", this.props);
if (loaded) {
return <Footstep data={data} />;
} else return <p>loading</p>;
}
}
Loaded should be true if response is successful and
Check if the the length of data is zero then show message
if(loaded && data.length === 0){
return <p>No Data available!</p>
}
else if (loaded) {
return <Footstep data={data} />;
}
else
return <p>loading</p>;
Can we do something like this?
if (loaded) {
return <Footstep data={data} />;
} else if(loaded && data.length === 0){
return <p>No Data available!</p>
} else return <p>loading</p>;

Most "react" way to have multiple different renderings

I hope this question isn't too subjective. I've been doing a lot of React development lately, and I have a header that used to have two different renderings.
Recently my client has asked for two additional renderings. I could nest conditionals in the renderings, but this feels messy to me and against good practices.
For example I have this:
{this.state.headerLoc ? (
<div className="secondary-nav">
...
</div>
) : (
<Back />
)}
I'd like to add two additional conditions to this - is there a "clean" way to do this without a bunch of additional nesting? Would refactoring/subcomponents be the only way to handle this condition?
EDIT: Pseudo-code example of what I want to do:
render {
if(page == 'page1') {
<renderX />
}
else if(page == 'page2') {
<renderX2 />
}
else if(page == 'page3') {
<renderX3 />
}
else if(page == 'page4') {
<renderX4 />
}
}
EDIT: Update for what I am doing now:
const HeaderArrays = {
FrontPage: ["/"],
SearchPage: ["cards", "map", "detail"],
NonSearchPage:[],
NonSearchPageHamburger:["settings"],
}
HeaderComponents() {
var routerPath = this.props.router.location.pathname;
for (const component in HeaderArrays) {
const value = HeaderArrays[component];
if(HeaderArrays[component].includes(routerPath)) {
return component;
}
return "FrontPage";
}
render() {
const ComponentToRender = this.HeaderComponents();
return(
<ComponentToRender />
You can just map components to a key in an object. this way you can omit a bunch of if else statements
const HeaderComponents = {
page1: Page1HeaderComponent,
page2: Page2HeaderComponent,
page3: Page3HeaderComponent,
page4: Page4HeaderComponent
}
and usage would be
render() {
const { page } = this.props // assuming page comes from props
const ComponentToRender = HeaderComponents[page]
return <ComponentToRender />
}
Here's an example to play with :)

Render React component from array values

I'm working on React with Symfony API and when I connect to my app, I've got a role defined by Symfony
It returns this if I'm an admin : ["ROLE_USER", "ROLE_ADMIN"]
It returns this if I'm a moderator : ["ROLE_USER", "ROLE_MODERATOR"]
It returns this if I'm a user : ["ROLE_USER"]
Currently my code is working fine and if I'm a user, it shows the user view, if I'm a moderator it shows the moderator view etc.
So my question is : Is there a better way to create a condition that will render the good component in function of my user role ?
render()
{
let content = "";
if (this.props.auth.user.roles.includes("ROLE_ADMIN")) {
content = <NavAdminDashboard />;
} else if (this.props.auth.user.roles.includes("ROLE_MODERATOR")) {
content = <NavModeratorDashboard />;
} else {
content = <NavUserDashboard />;
}
return (
<Fragment>
{content}
</Fragment>
)
}
I have checked this : Render component based on a variable - reactjs
It is better than my code but it only works if my roles render as string and not as array like my code.
You can achieve this in two ways
The first one is a little cleaner.
render(){
const {roles} = this.props.auth.user;
return (
<React.Fragment>
{ roles.include("ROLE_ADMIN") && <NavAdminDashboard /> }
{ roles.include("ROLE_MODERATOR") && <NavModeratorDashboard /> }
{ !roles.include("ROLE_ADMIN") && !roles.include("ROLE_MODERATOR) && <NavUserDashboard /> }
</React.Fragment>
)
}
You can also do that by creating two methods isAdmin and isModerator:
isAdmin = () => {
return this.props.auth.user.roles.include("ROLE_ADMIN");
}
isModerator = () => {
return this.props.auth.user.roles.include("ROLE_MODERATOR");
}
render() {
return (
<React.Fragment>
{ this.isAdmin() && <NavAdminDashboard /> }
{ this.isModerator() && <NavModeratorDashboard /> }
{ !this.isAdmin() && !this.isModerator() && <NavUserDashboard /> }
</React.Fragment>
)
}
Or you can add a isUser method to check if its only user
isUser = () => {
const {roles} = this.props.auth.user;
return roles.include("ROLE_USER") && roles.length === 1;
}
render() {
return (
<React.Fragment>
{ this.isAdmin() && <NavAdminDashboard /> }
{ this.isModerator() && <NavModeratorDashboard /> }
{ this.isUser() && <NavUserDashboard /> }
</React.Fragment>
)
}
I think your code is fine and doesn't necessary need to change. But I personally move the role logic either to external functions (that can be unit tested) or methods on the component. Eg:
get isAdmin() {
return this.props.roles.include('ADMIN');
}
get isUser() {
return !this.props.roles.some(role => role !== 'USER');
}
render() {
return <>
{this.isAdmin && <Admin />}
{this.isUser && <User />}
</>
}
Another alternative is to move the parsing of roles to a helper function and map the array to props. Eg:
<Component isAdmin={hasAdminRole(roles)} />
Both of these are nicer solutions if you ask me. But in the end, as long as the code works it might be good enough. You can always go back and refactor later.

Child component state not updated even after data source update (Diagram Included)

I am trying to build a react grid component that has design similar to the one shown in image.
(1) Someone passes raw data to grid as props, (2) which gets converted to multiple GridData objects and stored within GRID. (3) Those objects are iterated over in render function to render grid items. (4) Now, someone performs an action outside of grid (may be in toolbar or something), that triggers property change for some/all GridData objects stored within Grid (in this case select all). (5) This results in all grid items getting updated property (in this case all items will be selected).
However, when I update the attribute of an object in Grid, the child (GridItem) does not check the checkbox. How can I fix that?
The code for the design looks something like this:
Grid.js
class Grid extends Component {
constructor(props) {
super(props);
this.state = {
gridData: props.data,
};
}
componentWillReceiveProps(nextProps) {
this.setState({
gridData:
typeof nextProps.gridData !== 'undefined' && nextProps.gridData
? nextProps.gridData
: this.state.gridData,
});
}
// PubSub System to receive notification
subscriber(msg, data) {
if(msg === 'SELECT_ALL_ITEMS'){
this.state.gridData.forEach(gridItem => {
gridItem.setChecked(true);
}
}
renderGridItem(gridItem) {
return (
<GridItem
key={gridItem.getItemId()}
title={gridItem.getTitle()}
isChecked={gridItem.isChecked()}
/>
);
}
render() {
return (
<div>
{this.state.gridData !== 'undefined' && this.state.gridData ? (
this.state.gridData.map(gridItem => this.renderGridItem(gridItem))
) : (
<div />
)}
</div>
);
}
}
GridItem.js
class GridItem extends Component {
constructor(props) {
super(props);
this.state = {
isChecked: typeof props.isChecked !== 'undefined' && props.isChecked ? props.isChecked : false,
title: typeof props.title !== 'undefined' && props.title ? props.title : '',
},
};
}
render() {
const { classes } = this.props;
return (
<div>
<Checkbox
checked={this.state.isChecked}
/>
{this.state.properties.title}
</div>
);
}
}
GridData.js
export default class GridData {
constructor(item) {
this._title = item.title;
this._itemId = item.itemId;
}
getItemId() {
return this._entryId;
}
isChecked() {
return this._isChecked;
}
setChecked(isChecked) {
this._isChecked = isChecked;
}
getTitle() {
return this._title;
}
}
I think you need to put your subscriber into componentDidMount
This method is a good place to set up any subscriptions. If you do that, don’t forget to unsubscribe in componentWillUnmount()
And you have to update state with setState in your subscriber.
Calling setState() in componentDidMount method will trigger an extra rendering

Reusable component to wait for data

in many of my components I am fetching API data and therefor I need to wait until that data was loaded. Otherwise I am getting errors because some methods are, of course, not available.
My api query looks like this
componentDidMount() {
prismicApi(prismicEndpoint).then((api) =>
api.form('everything')
.ref(api.master())
.query(Prismic.Predicates.at("my.page.uid", this.props.params.uid))
.submit((err, res) => {
if (res.results.length > 0) {
this.setState({doc: res.results[0]});
} else {
this.setState({notFound: true});
}
}))
}
For that I've created this structure that I have been using in all of these documents:
render() {
if (this.state.notFound) {
return (<Error404 />);
} else if (this.state.doc == null || !this.state.doc) {
return (<Loading />);
} else {
return (
<div className="page">
{this.state.doc.getSliceZone('page.body').slices.map(function(slice, i){
return (<SliceZone slice={slice} key={i} />)
})}
</div>
)
}
}
I wanted to move this into a component called Document that looks like this here:
export default class Document extends React.Component {
static defaultProps = {
doc: null,
notFound: false
}
static propTypes = {
doc: React.PropTypes.oneOfType([
React.PropTypes.object,
React.PropTypes.array
]),
notFound: React.PropTypes.bool.isRequired
}
render() {
if (this.props.notFound) {
return (<Error404 />);
} else if (this.props.doc == null || !this.props.doc) {
return (<Loading />);
} else {
return (
<div className="page">
{this.props.children}
</div>
)
}
}
}
and then I tried to use it like this here:
<Document doc={this.state.doc} notFound={this.state.notFound}>
{this.state.doc.getSliceZone('page.body').slices.map(function(slice, i){
return (<SliceZone slice={slice} key={i} />)
})}
</Document>
Though on the second example the error messages are showing up quickly (until the data is loaded) and then disappear. What am I doing wrong? Why is the first example working and the second doesnt?
try this
<Document doc={this.state.doc} notFound={this.state.notFound}>
{ this.state.doc && this.state.doc.getSliceZone('page.body').slices.map(function(slice, i){
return (<SliceZone slice={slice} key={i} />)
})}
</Document>
in your variant, you see an error becuase this.state.doc is null, untill data is loaded, and you see null reference exception, looks like.
In 1st case, it does not calculate, in 2nd case it calculates first and then sent as a parameter "children" to your Document control

Categories