Initializing state in React without constructor - reactjs

I have a class component as shown below:
import React, { Component } from "react";
import Aux from "../../../hoc/Auxilary/Auxilary";
import ComponentDetails from "./SideBarLayoutDetails";
import DropDownDetails from "../UI/DropDown/DropDownDetails";
import Row from "../UI/Row/Row";
import "./Layouts.css";
import Dropdown from "../UI/DropDown/DropDown";
import Calendar from "../UI/Calendar/Calendar";
class SideBarLayout extends Component {
state = {
isActive: Array(DropDownDetails.length),
isDateActive: false,
}
DropDownArrowHandler = (index) =>
{
}
render()
{
const calendar = this.state.isDateActive ? <Calendar />:null;
return <Aux>
<div className = "SideBar-Central">
<Row Elems = {ComponentDetails.TopHeaders.elements}
Container = {ComponentDetails.TopHeaders.container}
/>
<Dropdown Elems = {DropDownDetails[0].DateFilter}
Container = {DropDownDetails[0].DateFilterContainer}
/>
{calendar}
</div>
</Aux>
}
}
export default SideBarLayout;
I want to initialize this.state.isActive in a loop fashion like this:
const initializedvalue = DropDownDetails.map(elem => elem.active);
and then use this initializedvalue to assign to this.state.isActive.
But I want to do this just when the component renders in the screen. What is the best way to do so? Should I use constructor? I don't prefer it as I get a warning using super(props). Please let me know the best way to do so. My end goal is to have a this.state.isActive array ready to be used in making the decisions about rendering the screen components.

First, forEach does not return any value as it is a void function. So try map function instead. This will return elements for which active is true (assuming active is a boolean type property in elem)
const initializedvalues = DropDownDetails.map(elem => elem.active);
Next, if you want to use this to set this.state.isActive after render, run it in componentDidMount(). Its a lifecycle function that runs after the initial render is done.

Related

Reactjs redux store changes but in component's props doesn't change

I'm tryin to show navigation depends on changes of categoryURL from
redux store and changing the state in other components. Redux changes the store and it works fine. But in my
component "this.props.categoryUrl" doesn't reflect on value. Can't
find out why?
import React, {Component} from 'react';
import NavigationItems from './NavigationItems/NavigationItems';
import classes from './Navigation.module.css';
import {connect} from 'react-redux';
const mapStateToProps = state => {
console.log(state)
return {
categoryURL: state.categoryUrl
};
};
class navigation extends Component {
componentDidMount() {
console.log(this.props.categoryUrl);
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('NAVIGATION!', this.props.categoryUrl);
}
render() {
let nav = null;
if (this.props.categoryUrl) {
nav = (
<div className={classes.Navigation}>
<NavigationItems/>
</div>
)
}
return (
<>
{nav}
</>
)
}
}
export default connect(mapStateToProps, null)(navigation);
In "normal" React it is needed to use <Navigation/> (Capital letter at the beginning) instead of <navigation/>. Also, If <Navigation/> is being used by another React component then it might be needed to add code that will be executed inside <Navigation/> to refresh the component where you are using <Navigation/> (some kind of callback passed to <Navigation/>). It is this the way or move all the <Navigation/>'s code to the component where you are using <Navigation/>. This is how I solved this kind of problem.

How can I get the native PIXI object from a react-pixi-fiber React component?

In an app wrapped with withApp from this:
import { withApp } from "react-pixi-fiber";
And some code that looks a little like this:
class Foo extends React.Component {
// ...
eventHandler(evt) {
console.log("Event target =", evt.target);
}
render() {
let comp = (<Sprite interactive texture={...} pointerup={eventHandler} {/* ... */} />);
console.log("Component =", comp);
return (comp);
}
}
Doing this, the object that is logged as the "Event target" is a native PIXI Sprite object, which gives me access to methods like getBounds(). I'd like to be able to access this same sort of data from the comp variable (which I would then store somewhere), but when I log that, the object I get is something different. It has a $$typeof: Symbol(react.element), so I presume it's just a React object. I'd like to find a way to get access to the PIXI object associated with it so that I can do use that object later for doing things like bounds checking on an interactive setup with various other elements.
Is there a way to do this? Or: How can I do bounds checking on interactivity into an object that isn't the current target of an event from e.g. pointerup, pointermove, etc.?
It's been a while, but if you're still looking to solve this, you need to use a ref on your Sprite component. This isn't specific to react-pix-fiber, just standard React behavior. Using ReactDOM the ref would give you access to the html element, with PIXI and react-pixi-fiber, it gives you the PIXI display object.
import React, { createRef, Component } from "react";
class Foo extends Component {
constructor() {
super();
this.ref = createRef();
}
eventHandler() {
console.log(this.ref.current);
}
render() {
return (
<Sprite
interactive
texture={...}
pointerup={this.eventHandler.bind(this)}
/>
);
}
}
Besides the event handler, this.ref will be available in other lifecycle methods. Before render though, this.ref.current will be undefined.
Alternatively, you could use function components and hooks, either the useCallback hook or a combination for useRef and useEffect.
import React, { useCallback } from "react";
const Foo = () => {
const ref = useCallback(sprite => {
console.log(sprite);
}, []);
return (
<Sprite
interactive
ref={ref}
texture={...}
pointerup={this.eventHandler.bind(this)}
/>
);
}
import React, { useEffect, useRef } from "react";
const Foo = () => {
const ref = useRef();
useEffect(() => {
console.log(ref.current);
}, []);
return (
<Sprite
interactive
ref={ref}
texture={...}
pointerup={this.eventHandler.bind(this)}
/>
);
}
I created working examples of each of these methods here (see the BunnyClass, BunnyCallback and BunnyRef files):
https://codesandbox.io/s/hardcore-maxwell-pirh3

React - Conditionally Show Block Based on Query String Parameter Value

I have an app using React. It includes the React Router. In one of my components, I need to read the query string, and conditionally show one block if the query string parameter has a value. If the value is not present in the query string, I want to show another block.
import React, {Component} from 'react';
import {Container} from 'reactstrap';
import {NavMenu} from './NavMenu';
export class Layout extends Component {
static displayName = Layout.name;
render() {
return {
<div>
<NavMenu /> <!-- I want to hide this is query string has hideNav=true -->
<Container> <!-- I want to use a fluid layout if the query string has hideNav=true -->
{this.prop.children}
</Container>
</div>
}
}
}
How do I conditionally render content based on the query string value.
Just to represent a quick example let me suggest a URL with a query string parameter what the code operates with. It's called hideNav as below:
https://yourawesomewebsite.com/?hideNav=true
As a first step:
We need to get the query string what you need work with in your render method. There are quite a couple of options to get the query parameters, let me summarize here:
1. Using the window object
let queryString = new URLSearchParams(window.location.search);
let hideNav = queryString.get('hideNav');
Read further about URLSearchParams in this link. Highlighted from the mentioned URL:
The URLSearchParams interface defines utility methods to work with the query string of a URL.
2. Using the React Router way
let queryString = this.props.match.params;
let hideNav = queryString.hideNav;
Please follow this link if you want to read further. Additionally let me highlight below the key point here:
params - (object) Key/value pairs parsed from the URL corresponding to the dynamic segments of the path
As a second step:
The code needs to use the conditional rendering based on the value.
import React, {Component} from 'react';
import {Container} from 'reactstrap';
import {NavMenu} from './NavMenu';
export class Layout extends Component {
static displayName = Layout.name;
render() {
const hideNav = // here you can decide based on the above explanation which one you want to use
return {
<div>
{ !hideNav ? <NavMenu /> : null }
<Container fluid={hideNav}>
{this.prop.children}
</Container>
</div>
}
}
}
About fluid container you can read further here:
fluid (boolean) - Allow the Container to fill all of it's available horizontal space.
So basically rendering NavMenu once the hideNav value is true other than that React renders null. On the Container the code is using the fluid property to manipulate the horizontal space.
Assuming you have params in your react router routes you can get those via this.props.match.params:
export class Layout extends Component {
static displayName = Layout.name;
render() {
const {hideNav} = this.props.match.params;
return {
<div>
{!hideNav && <NavMenu />} // Render NavMenu if hideNav is false
<Container fluid={hideNav}>
{this.prop.children}
</Container>
</div>
}
}
}
Hi check these conditions based example
class Layout extends Component {
constructor(props) {
super(props);
this.state = {
hideNave: false
}
}
componentDidMount() {
axios.get('http://url')
.then(res => {
if (res.date) {
this.setState({
hideNave: true
})
}
});
}
render() {
return
(<div>
{ this.state.hideNave ? (<NavMenu />) : (<Container> {this.prop.children} </Container>) }
</div>)
}
}

How to get the data from React Context Consumer outside the render

I am using the new React Context API and I need to get the Consumer data from the Context.Consumer variable and not using it inside the render method. Is there anyway that I can achieve this?
For examplify what I want:
console.log(Context.Consumer.value);
What I tested so far: the above example, tested Context.Consumer currentValue and other variables that Context Consumer has, tried to execute Context.Consumer() as a function and none worked.
Any ideas?
Update
As of React v16.6.0, you can use the context API like:
class App extends React.Component {
componentDidMount() {
console.log(this.context);
}
render() {
// render part here
// use context with this.context
}
}
App.contextType = CustomContext
However, the component can only access a single context. In order to use multiple context values, use the render prop pattern. More about Class.contextType.
If you are using the experimental public class fields syntax, you can use a static class field to initialize your contextType:
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/* render something based on the value */
}
}
Render Prop Pattern
When what I understand from the question, to use context inside your component but outside of the render, create a HOC to wrap the component:
const WithContext = (Component) => {
return (props) => (
<CustomContext.Consumer>
{value => <Component {...props} value={value} />}
</CustomContext.Consumer>
)
}
and then use it:
class App extends React.Component {
componentDidMount() {
console.log(this.props.value);
}
render() {
// render part here
}
}
export default WithContext(App);
You can achieve this in functional components by with useContext Hook.
You just need to import the Context from the file you initialised it in. In this case, DBContext.
const contextValue = useContext(DBContext);
You can via an unsupported getter:
YourContext._currentValue
Note that it only works during render, not in an async function or other lifecycle events.
This is how it can be achieved.
class BasElement extends React.Component {
componentDidMount() {
console.log(this.props.context);
}
render() {
return null;
}
}
const Element = () => (
<Context.Consumer>
{context =>
<BaseMapElement context={context} />
}
</Context.Consumer>
)
For the #wertzguy solution to work, you need to be sure that your store is defined like this:
// store.js
import React from 'react';
let user = {};
const UserContext = React.createContext({
user,
setUser: () => null
});
export { UserContext };
Then you can do
import { UserContext } from 'store';
console.log(UserContext._currentValue.user);

Render returned no data - trying to call component multiple times in forEach

I am new to React and am really struggling.
I want to create a small app that:
Reads in data from my data.js file (an object)
Outputs it each sub-object info into a card component
I have created a component called Lister where the data is imported, and iterated over using forEach.
I then want to call the Card component and output the data on the page in this component for each sub-object.
However I keep getting the error that the render in my Lister component does not return anything.
It is a small component so here it is in full:
import React from 'react';
import data from "../../data/data";
import Card from "../card";
class Lister extends React.Component {
render() {
return (
Object.keys(data()).forEach(function(key) {
<Card data={data()[key]}/>
})
)
}
}
export default Lister;
For React you'll want to be using .map to handle your loops. Also any time you're using JSX, remember you add the open and closing curly braces {} (you were missing one right before Object). Lastly, everything inside of the return inside of render needs to be wrapped in a single root node like a <div> for example.
Here's an example of how you might rewrite this:
import React from 'react';
import data from "../../data/data";
import Card from "../card";
class Lister extends React.Component {
render() {
const items = data();
return (
<div>
{Object.keys(items).map(function(key, index) {
return <Card key={index} data={items[key]}/>
})}
</div>
);
}
}
export default Lister;
I think you should use .map instead of .forEach. With .forEach, you can handle that like this:
render() {
const items = data();
let cards=[];
Object.keys(items).forEach(function(key,i) {
objArray.push(<Card key={i} data={items[key]})
});
return (<div>{cards}</div>)
}

Resources