I have a set of items that needs to be shown in the UI, like a header and list of items under it. There is a parent component where I am passing this data to a file that is shown below. Based on this the parent-child layout is shown. Now I need to expand/collapse based on the click of the header.
There is a class "open" and "close " that can be attached to the div. Based on it the it gets collapse/expands. The point is how do it item wise
Can someone help
import React from "react";
import Child from "./Child";
import Parent from "./Parent";
export default class Helper extends React.Component{
constructor(props: any) {
super(props);
this.state = {
parent:{},
children:{},
};
}
componentDidMount() {
this.setParentValue();
this.setChildValue();
}
render() {
const { parent, children } = this.state;
const { name } = this.props;
return (
<>
<div className="an-panel expand-panel expand-close">
<div className="an-panel-header">
<div className="title-holder">
<span className="toggle-icon far fa-plus-square" />
<span className="toggle-icon far fa-minus-square" />
<h5>{name}</h5>
</div>
<div className="action-holder">
<div className="status-holder">
<Parent
parent = {parent}
onSelect={this.handleParentClick}
/>
</div>
</div>
</div>
{children.map(({ id, name },id) => (
<div className="an-panel-body" key={id}>
<ul className="applications-list-holder">
<li>
<div className="name">{name}</div>
<div className="status">
<Child
children={children}
onSelect={this.setChildSwitchValue}
/>
</div>
</li>
</ul>
</div>
))}
</div>
</>
);
}
}
Ok let me explain it to you, here is your code
import React from "react";
import Child from "./Child";
import Parent from "./Parent";
export default class Helper extends React.Component{
constructor(props: any) {
super(props);
this.state = {
parent:{},
children:{},
navBarStatus: false,
};
}
componentDidMount() {
this.setParentValue();
this.setChildValue();
}
changeNavBar = (e, status)=>{
this.setState({navBarStatus: !status});
}
render() {
const { parent, children } = this.state;
const { name } = this.props;
return (
<>
<div className={`an-panel expand-panel ${this.state.navBarStatus ? "expand-open" : "expand-close"}`}>
<div className="an-panel-header" onClick={(e)=>this.changeNavBar(e, this.state.navBarStatus)}>
<div className="title-holder">
<span className="toggle-icon far fa-plus-square" />
<span className="toggle-icon far fa-minus-square" />
<h5>{name}</h5>
</div>
<div className="action-holder">
<div className="status-holder">
<Parent
parent = {parent}
onSelect={this.handleParentClick}
/>
</div>
</div>
</div>
{children.map(({ id, name },id) => (
<div className="an-panel-body" key={id}>
<ul className="applications-list-holder">
<li>
<div className="name">{name}</div>
<div className="status">
<ChildSetting
children={children}
onSelect={this.setChildSwitchValue}
/>
</div>
</li>
</ul>
</div>
))}
</div>
</>
);
}
}
You can see I have taken a new property in state navBarStatus. Based on navBarStatus value I am changing CSS class which will expand/close your attached div
Related
I am a beginner in using the React JS framework. Based on the official React JS documentation, an example is given for changing the state of a component that has a connected hierarchy. But in my case this time I split the components for Header and Main separately.
index.js
ReactDOM.render(
<React.StrictMode>
<Header />
<Main />
</React.StrictMode>,
document.getElementById('root')
);
In the Header component I also have another sub component that functions to activate / deactivate the sidebar which is also a sub menu for the Main component.
Header.js
import { BtnSidebarOnClick } from './Sidebar';
const Header = () => {
return (
<header className="header">
<div className="header__logo">
<BtnSidebarOnClick />
<div className="header__logo_img">
<a className="link"
href="/">
<img src=""
alt="Schedule App" />
</a>
</div>
</div>
<nav className="header__nav">
...
</nav>
</header>
);
}
export default Header;
Main.js
import { Sidebar } from './Sidebar';
const Main = () => {
return (
<main className="main">
<Sidebar />
<div className="main__content">
...
</div>
</main>
);
}
export default Main;
Notice that the BtnSidebarOnClick and Sidebar components are not connected. In my case, this time I want to make the Sidebar component accept state to detect whether the button contained in the BtnSidebarOnClick component is clicked / not.
Sidebar.js
class BtnSidebarOnClick extends React.Component {
constructor(props) {
super(props);
this.state = { onClick: false };
}
handleClick() {
this.setState(state => ({ onClick: !state.onClick }));
}
render() {
return (
<div className="header__logo_btn">
<div className="button button--hover button--focus"
role="button"
tabIndex="0"
onClick={this.handleClick.bind(this)}>
<i className="material-icons">menu</i>
</div>
</div>
);
}
}
const Sidebar = () => {
return (
<div className="main__sidebar"> {/* set style if BtnSidebarOnClick clicked */}
<div className="main__sidebar_menu">
<div className="tag-link">
<a className="link link--hover link--focus link--active"
href="/">
<i className="material-icons">insert_drive_file</i>
<span className="link-title">Files</span>
</a>
</div>
</div>
</div>
);
}
export { Sidebar, BtnSidebarOnClick };
So how do you set these two components to receive the same state?
TLDR; You should pull out the button state into the parent and pass it into the children component.
By the way, it is a common way to have file App.js for your main Application file. In your case, it should be like this:
index.js
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
App.js
class App extends React.Component {
constructor(props) {
super(props);
this.state = { isClicked: false };
}
handleClick() {
this.setState(state => ({ isClicked: !state.isClicked }));
}
render() {
return (
<div>
<Header onClick={this.handleClick} /> // --> notice
<Main isClicked={this.state.isClicked} /> // --> notice
</div>
)
}
}
Header.js
import BtnSidebar from './BtnSidebar';
const Header = (props) => {
return (
<header className="header">
<div className="header__logo">
<BtnSidebar onClick={props.onClick} /> // --> notice
<div className="header__logo_img">
<a className="link"
href="/">
<img src=""
alt="Schedule App" />
</a>
</div>
</div>
<nav className="header__nav">
...
</nav>
</header>
);
}
Main.js
import Sidebar from './Sidebar';
const Main = (props) => {
return (
<main className="main">
<Sidebar isClicked={props.isClicked} /> // --> notice
<div className="main__content">
...
</div>
</main>
);
}
BtnSidebar.js
const BtnSidebar = (props) => {
return (
<div className="header__logo_btn">
<div className="button button--hover button--focus"
role="button"
tabIndex="0"
onClick={props.onClick} // --> notice
>
<i className="material-icons">menu</i>
</div>
</div>
);
}
Sidebar.js
const Sidebar = (props) => {
return (
<div
className={
props.isClicked ? 'main__sidebar-clicked' : 'main__sidebar' // --> notice
}
>
<div className="main__sidebar_menu">
<div className="tag-link">
<a className="link link--hover link--focus link--active"
href="/">
<i className="material-icons">insert_drive_file</i>
<span className="link-title">Files</span>
</a>
</div>
</div>
</div>
);
}
I am a newbie in React and I am trying to pass props from one React component to another. Please consider my code below and tell me what could I possibly doing wrong.
As you will notice, I am trying to do so with this.props.value, but all I got in the console is "undefined". I managed to run the code by putting all HTML elements in one component and it was working perfectly fine.
class Editor extends React.Component {
constructor(props) {
super(props);
this.state = {
input: defaultTxt
};
this.inputChanges = this.inputChanges.bind(this);
}
inputChanges(e) {
this.setState({
input: e.target.value
});
}
render() {
return (
<div>
<div id="editorBar">
Editor
<i className="fa fa-expand expand" />
</div>
<textarea
id="editor"
style={editorStyle}
value={this.state.input}
onChange={this.inputChanges}
placeholder={defaultTxt}
/>
</div>
);
}
}
//preview
class Previewer extends React.Component {
render() {
return (
<div>
<div id="previewerBar">
Preview
<i className="fa fa-expand expand" />
</div>
<div
id="preview"
style={viewerStyle}
dangerouslySetInnerHTML={{ __html: this.props.value }}
/>
</div>
);
}
}
//wrapper
class Wrapper extends React.Component {
render() {
return (
<div id="wrapper">
<Editor />
<Previewer />
</div>
);
}
}
const defaultTxt = `Some default text`;
ReactDOM.render(<Wrapper />, document.getElementById('root'));
It should look like this:
class Editor extends React.Component {
render() {
return (
<div>
<div id="editorBar">
Editor
<i className="fa fa-expand expand" />
</div>
<textarea
id="editor"
style={editorStyle}
value={this.props.input}
onChange={this.props.inputChanges}
placeholder={defaultTxt}
/>
</div>
);
}
}
//preview
class Previewer extends React.Component {
render() {
return (
<div>
<div id="previewerBar">
Preview
<i className="fa fa-expand expand" />
</div>
<div
id="preview"
style={viewerStyle}
dangerouslySetInnerHTML={{ __html: this.props.value }}
/>
</div>
);
}
}
//wrapper
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state = {
input: defaultTxt
};
this.inputChanges = this.inputChanges.bind(this);
}
inputChanges(e) {
this.setState({
input: e.target.value
});
}
render() {
return (
<div id="wrapper">
<Editor input={this.state.input} inputChanges={this.inputChanges}/>
<Previewer value={this.state.input}/>
</div>
);
}
}
const defaultTxt = `Some default text`;
ReactDOM.render(<Wrapper />, document.getElementById('root'));
The idea is that the Wrapper component will be the one which hold the state and control the state change. The Editor and Previewer are its children which receive data to display and invoke the callback prop.
If two components share state lift the state to the parent component - in this case Wrapper. And since neither of the two children components have state they can be coded as stateless functions.
function Editor({ text, handleChange }) {
return (
<div>
<div id="editorBar">Editor
<i className="fa fa-expand expand" />
</div>
<textarea id="editor" value={text} onChange={handleChange} />
</div>
);
}
function Previewer({ text }) {
return (
<div>
<div id="previewerBar">Preview
<i className="fa fa-expand expand"></i>
</div>
<div id="preview" dangerouslySetInnerHTML={{__html: text}}></div>
</div>
);
}
class Wrapper extends React.Component {
constructor(props) {
super(props);
this.state={ input: props.defaultText }
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({ input: e.target.value });
}
render() {
return (
<div id="wrapper">
<Editor text={this.state.input} handleChange={this.handleChange} />
<Previewer text={this.state.input} />
</div>
);
}
}
const defaultText = 'Some default text';
ReactDOM.render(<Wrapper defaultText={defaultText} />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
I'm following the example here: https://redux-form.com/6.6.3/examples/wizard/
I've managed to make everything I needed up until now, but I'm getting stuck on how to make custom radio buttons.
This is what I have so far, but I can't get the radio button to change when clicking on the divs that represent it
import React, { Component } from 'react'
import './pictureCard.css'
import '../../../../app.css'
import MaterialIcon from 'react-google-material-icons'
import { Field } from 'redux-form'
export default class PictureCard extends Component {
constructor(props) {
super(props)
this.state = {
isChecked: false
}
}
handleTick = event => {
const card = event.target
card.classList.toggle('question__checkbox--selected')
this.setState(prevState => {
return { isChecked: !prevState.isChecked }
})
}
render() {
const {
tabOrder,
cardName,
cardKey,
cardLabel,
thumbnail,
thumbnailAlt
} = this.props
return (
<li
className="question__choice"
tabIndex={tabOrder}
onClick={this.handleTick}
>
<Field
name={cardName}
type="radio"
component="input"
value={cardLabel}
checked={this.state.isChecked}
/>
<div className="question__tick-wrap">
<MaterialIcon icon="check" />
</div>
{thumbnail === undefined ? null : (
<div className="question__image-wrap">
<img src={thumbnail} alt={thumbnailAlt} />
</div>
)}
<div className="question__text-wrap flex flex--center-vertical">
<div className="question__label">
<div className="question__letter">
<span>{cardKey}</span>
</div>
</div>
<div className="question__text-label">{cardLabel}</div>
</div>
<div className="question__bg" />
</li>
)
}
}
I can programatically change the value, but it doesn't update in the store, and I don't know why :(
This is what I tried:
import React, { Component } from 'react'
import './pictureCard.css'
import '../../../../app.css'
import MaterialIcon from 'react-google-material-icons'
import { Field } from 'redux-form'
export default class PictureCard extends Component {
constructor(props) {
super(props)
this.state = {
valueTest: false
}
}
handleTick = event => {
const card = event.target
card.classList.toggle('question__checkbox--selected')
this.setState({ valueTest: 'Hello' })
}
render() {
const {
input,
tabOrder,
cardName,
cardKey,
cardLabel,
thumbnail,
thumbnailAlt
} = this.props
return (
<li
className="question__choice"
tabIndex={tabOrder}
onClick={this.handleTick}
>
<input
{...input}
name={cardName}
value={this.state.valueTest}
type="text"
tabIndex={tabOrder}
/>
<div className="question__tick-wrap">
<MaterialIcon icon="check" />
</div>
{thumbnail === undefined ? null : (
<div className="question__image-wrap">
<img src={thumbnail} alt={thumbnailAlt} />
</div>
)}
<div className="question__text-wrap flex flex--center-vertical">
<div className="question__label">
<div className="question__letter">
<span>{cardKey}</span>
</div>
</div>
<div className="question__text-label">{cardLabel}</div>
</div>
<div className="question__bg" />
</li>
)
}
}
I have a userlist which contains name and email id of each user. I want to display it using the .map() method on userlist state variable. I have created displayusers() function to display the users but I am getting failed to compile error.
Code:
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
userlist:[
{'name':'Rohan Singh',
'email':'rohan#gmail.com'
},
{'name':'Mohan Singh',
'email':'mohan#gmail.com'
},
{'name':'Rakesh Roy',
'email':'rakesh#gmail.com'
},
{'name':'Sunil Shah',
'email':'sunil#gmail.com'
}]
}
}
displayusers(){
return this.state.userlist.map( user => {
return(
<div className="item-card">
<div className="sub">
<div className="type">Username: {user.name}</div>
<div className="members">Email: {user.email}</div>
</div>
<div className="del-wrap">
<img src={require("../../images/cancel.svg")}/>
</div>
</div>
);
})
}
render() {
return(
<div className="users-wrap">
<h1>Users</h1>
<div className="task-content">
<div className="user-wrap">
<div className="users">
{this.displayusers()}
</div>
</div>
</div>
</div>
);
}
}
export default App;
I think you forgot about adding a key attribute to the element and there's missing </div> closing tag in your map function.
See the corrected code:
displayusers(){
return this.state.userlist.map( user => {
return(
<div className="item-card" key={user.name}>
<div className="sub">
<div className="type">Username: {user.name}</div>
<div className="members">Email: {user.email}</div>
</div>
<div className="del-wrap">
<img src={require("../../images/cancel.svg")}/>
</div>
</div>
);
});
}
You need to bind your displayusers function to this. You can do that in the constructor.
Update your code as following:
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
userlist:[
{'name':'Rohan Singh',
'email':'rohan#gmail.com'
},
{'name':'Mohan Singh',
'email':'mohan#gmail.com'
},
{'name':'Rakesh Roy',
'email':'rakesh#gmail.com'
},
{'name':'Sunil Shah',
'email':'sunil#gmail.com'
}]
};
this.displayusers = this.displayusers.bind(this); // you need to add this line
}
displayusers(){
return this.state.userlist.map((user, index) => {
return(
<div className="item-card" key={index}>
<div className="sub">
<div className="type">Username: {user.name}</div>
<div className="members">Email: {user.email}</div>
</div>
<div className="del-wrap">
<img src={require("../../images/cancel.svg")}/>
</div>
);
})
}
render() {
return(
<div className="users-wrap">
<h1>Users</h1>
<div className="task-content">
<div className="user-wrap">
<div className="users">
{this.displayusers()}
</div>
</div>
</div>
</div>
);
}
}
export default App;
I have 3 React components:
-Home - need to display the component here when image is
clicked from the Header component
-Header- Contains the image tag that will be clicked to
show the AllSites Component.
-AllSites - component that needs displayed in Home component when Image is
clicked in the Header component.
Header
export class Header extends React.Component<any, any> {
private readonly searchServerUrl = "";
private appButtonElement: HTMLElement;
constructor(props: any) {
super(props);
this.state = { showAppMenu: false };
}
render() {
const { showAppMenu } = this.state;
const { className, navItems, singleColumn, appItems } = this.props;
return (
<header className={className}>
<div className="app-icon">
<button className="nav-button" onClick={() => this.toggleAppMenu()} ref={(menuButton: any) => this.appButtonElement = menuButton}><i className="ms-Icon ms-Icon--Waffle" aria-hidden="true"></i></button>
</div>
***When image is clicked, show the <AllSites/> component in the HomeComponent below.***
<img src="/Styles/Images/logo/loop-logo-white.png" className="nav-logo" onClick={} />
{showAppMenu ? <ApplicationMenu navItems={appItems} targetElement={this.appButtonElement} onDismiss={() => this.onDismiss()} /> : null}
<div className="nav-container"><TopNavigation classNam
e={className} navItems={navItems} singleColumn={singleColumn} /></div>
<div className="search-container">
<SearchBox onSearch={(searchTerm: string) => this.executeSearch(searchTerm)} />
</div>
</header>
);
}
Home
export class HomeComponent extends React.Component<any, any> {
constructor(props: any) {
super(props);
this.state = { navItems: [], appItems: [], singleColumnLayout: false, showAllSites: false };
}
componentDidMount() {
this.checkWidth();
window.addEventListener("resize", this.checkWidth.bind(this));
this.fetchNavigation()
.then(nav => this.setState({ navItems: nav }));
this.fetchAppIcons()
.then(icons => this.setState({ appItems: icons }));
}
componentWillUnmount(): void {
window.addEventListener("resize", this.checkWidth.bind(this));
}
render() {
const { navItems, appItems, singleColumnLayout } = this.state;
return (
<Fabric>
<Header navItems={navItems} appItems={appItems} singleColumn={singleColumnLayout} />
<div className="main-container">
<AlertBar />
<div className="main-content">
<div className="ms-Grid">
When the image tag is clicked, I need to render the <AllSites/> component here
<Hero singleColumn={singleColumnLayout} />
<div className="ms-Grid-row">
<div className="ms-Grid-col ms-sm12 ms-xl4 webpart-container">
<UpcomingEvents />
</div>
<div className="ms-Grid-col ms-sm12 ms-xl4 webpart-container">
<EmployeeNews />
</div>
<div className="ms-Grid-col ms-sm12 ms-xl4 webpart-container">
<div className="ms-Grid-row">
<div className="ms-Grid-col ms-sm12 webpart-container">
<IndustryNews />
</div>
<div className="ms-Grid-col ms-sm12 webpart-container">
<Quote />
</div>
</div>
</div>
</div>
</div>
<Footer navItems={navItems} />
</div>
</div>
</Fabric>
);
}
In the simplest approach you will need a common parent component for your Home and Header that will hold some shared state for them and that will pass a callback to update this state as a prop to Header. In the shared state you need a flag that will be responsible for showing/hiding AllSites component, this flag you will pass as a prop to Home.
You can see a basic example here
If you need a more advanced state management solution, you can check redux library