how to show/hide component in react with mobX - reactjs

i have some trouble here, so i make simple contact list and i want the contact card in the right appears if i click the contact list in the left, maybe you could give me advice how to do that , so far i just looping each component and i plan to make onClick state to hidden or show the component but i think it's not good solution
gere's my code so far:
import React from 'react'
import ContactTable from './ContactList'
import ContactCard from './ContactCard'
import { observer, inject } from 'mobx-react'
import DevTools from 'mobx-react-devtools'
import styles from './contact.css'
//import Component
#inject('store') #observer
export default class Contact extends React.Component {
componentDidMount() {
this.props.store.contact.loadParent()
}
handleClick = () => {
this.props.store.contact.selected = !this.props.store.contact.selected
}
render() {
var data = this.props.store.contact.fetchedData
console.log(this.props.store.contact.selected)
return (
<div>
<DevTools />>
<ContactTable data={data} onClick={this.handleClick.bind(this)} />
{
this.props.store.contact.selected ? <ContactCard person={data} /> : null
}
</div>
)
}
}
<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>

Related

How to send data from one component to another in nextjs

I'm working in nextjs.I have header component and in order to show header in all other pages ,overrided app.js with _app.js .Header has 2 navigation link usersList and users.
Now I want to send data from header component to another page say usersList and users on click of submit in header.How we can achieve that .
I know that we can use context .I'm using class based component don't know weather we can use context.
Is there any other solution to this problem..
Please help
header.js
class HeaderComponent extends Component {
onSearch(event){
//some code
}
render() {
return (
<div className="navbar">
<Input id="search-input" className="text-box" placeholder="Enter name or Email.." onKeyDown={($event)=>this.onSearch($event)} prefix={<Icon type="search" onClick={()=>this.onSearch} ></Icon>}></Input>
</div>
)
}
}
export default HeaderComponent
Layout.js
import React, { Component } from 'react';
import Header from './Header';
class Layout extends Component {
render () {
const { children } = this.props
return (
<div className='layout'>
<Header />
{children}
</div>
);
}
}
_app.js
import React from 'react';
import App from 'next/app';
import Layout from '../components/Layout';
export default class MyApp extends App {
render () {
const { Component, pageProps } = this.props
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
}
userList.js
class AppUser extends Component {
render() {
return (
<Table
rowKey={data._id}
columns={this.columns1}
onExpand={this.onExpand}
dataSource={data}
/>
)
}
}
EDIT :
can we achieve it through props
You can use ReactRedux to create a store and have it accessible from all components.
https://redux.js.org/api/store [1]

imported component is not displayed

i've a component that i import, but its not displayed on the page.
this is my app.js file. i imported the <player/>component but it is not getting displayed properly on the browser.
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import { player } from "./player";
class App extends Component {
render() {
return (
<div className="App">
<div>
<player />
</div>
</div>
);
}
}
export default App;
this is the contents of the player.js
import React from "react";
import { Button } from "evergreen-ui";
export default class player extends React.Component {
constructor(...args) {
super(...args);
this.state = {
shoot: 0
};
}
shoot() {
this.setState.shoot = Math.floor(Math.random() * Math.floor(3));
}
render() {
return (
<div>
<h1>hello there</h1>
<h1>{this.state.shoot}</h1>
<Button onClick={() => this.shoot}>Shoot another
value</Button>
</div>
);
}
}
In your code, you've exported your player component as a default export
export default class player extemds React.Component
But in your import of it in the other file, you're importing it as a named export
import { player } from "./player";
Try importing it without the curly braces as you would with a default export
import player from "./player";
You are doing two mistakes:
1. Importing the component in the wrong way
2. Rendering the component in the wrong way
Solution
The component should be imported without the curly braces
The react component "player" is supposed to start with capital letters i.e. it should be renamed as Player
Below is the working code I have tried in my local machine. It only modifies App.js
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import Player from "./player"; // imported without curly braces and with capital first letter
class App extends Component {
render() {
return (
<div className="App">
<div>
<Player /> {/* Rendering the correct way */}
</div>
</div>
);
}
}
export default App;
Sidenote
In player.js, you are setting the state in the wrong fashion, it won't work because:
setState is a method and not a object
this is not binded with method shoot. It will throw error something like "cannot read this of undefined" or something
Modify your player.js as following:
import React from "react";
import { Button } from "evergreen-ui";
export default class player extends React.Component {
constructor(...args) {
super(...args);
this.state = {
shoot: 0
};
}
shoot = ()=>{
this.setState({
shoot: Math.floor(Math.random() * Math.floor(3)),
});
}
render() {
return (
<div>
<h1>hello there</h1>
<h1>{this.state.shoot}</h1>
<Button onClick={() => this.shoot()}>Shoot another
value</Button>
</div>
);
}
}
You have two main issues:
1) You export as default and then your import is wrong.
If you export as:
export default class player extemds React.Component
Then you need to import as:
import player from "./player";
2) Components must start uppercase, otherwise React thinks that they are simple HTML tags and not components.
So you must change player to Player everywhere

List generated in constructor not calling event handler

I am generating a list on elements inside the constructor and rendering it inside render function. I am properly binding this to the event handler, but still not able to call the event handler. I have created a codepen
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(<App boxes="9" />, document.getElementById('root'));
App.js
import React, { Component } from 'react';
import Box from './Box';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.play = this.click.bind(this);
this.boxes = [];
for (let i = 0; i < props.boxes; i++) {
this.boxes.push(<Box key={i} onClick={this.play} />);
}
}
click() {
console.log('called click');
}
render() {
return <div className="App">{this.boxes}</div>;
}
}
export default App;
However it works fine if I bind the onClick function inside the render function, or even when I call the onClick prop inside Box.js
Box.js
import React, { Component } from 'react';
import './Box.css';
class App extends Component {
render() {
return <div className="box">{this.props.display}</div>;
// return (
// <div onClick={this.props.onClick} className="box">
// {this.props.display}
// </div>
// ); -- this helps me trigger the event handler on App component
}
}
export default App;
Can you help me add the event handler without specifying the onclick handler twice i.e on both App component and Box component
Can you help me add the event handler without specifying the onclick
handler twice i.e on both App component and Box component
You have to specify it twice, once to give the function to the Box component, and second time, to let the Box component decide when to call that function; this is what you do in your second example, which is commented out.
Otherwise, how do you imagine it specifying it only once?
I suggest to strore the boxes in the state and refer the onClick within the render method, not in constructor.
You can completely get rid of constructor btw simply using arrow functions as methods.
const Box = ({onClick, label}) => (
<div onClick={onClick}>{label}</div>
)
class App extends React.Component {
state = {
boxes: [
{id: 1, label: 'Box label 1'},
{id: 2, label: 'Box label 2'},
]
}
handleClick = () => {
console.log('box click');
}
render() {
const { boxes } = this.state;
return (
<div className="App">
{boxes.map(box => (
<Box key={box.id} label={box.label} onClick={this.handleClick} />))}
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

React and d3-graphviz

I'm trying to render a graphviz graph from a dotfile in my React Component. I keep running into errors I don't understand. If anyone could shed some light I would be grateful.
import React from 'react';
import dotSrc from '../../assets/visualize_dotfile.dot';
import Viz from 'viz.js';
import * as d3 from 'd3'
import * as d3Graphviz from 'd3-graphviz';
class Visualization extends React.Component {
setGraph() {
console.log('DOT source =', dotSrc);
const dotSrcLines = dotSrc.split('\n');
d3.select(".graph").graphviz().renderDot(dotSrc);
}
render(){
return (
<div className="graph">
{this.setGraph}
</div>
)
}
}
export default Visualization;
I've also tried:
import React, { Component } from 'react';
import { render } from 'react-dom';
import dotSrc from '../../assets/visualize_dotfile.dot';
import Viz from 'viz.js';
import HTMLReactParser from 'react-html-parser';
const graph = Viz({ files: [ { path: dotSrc } ] });
class Visualization extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
}
render() {
return (
<div>
<div>
{HTMLReactParser(graph)}
</div>
</div>
);
}
}
render(<Visualization />, document.getElementById('root'));
To no avail. Neither Viz nor GraphViz wants to read my dotfile though I'm not sure I'm using the correct syntax either.
Thank you in advance.
It's not exactly clear what you want to do and what errors you are getting.
This code at least generates a graph from a static string when the button is clicked:
import React, { Component } from 'react';
import * as d3 from 'd3'
import * as d3Graphviz from 'd3-graphviz';
var dotSrc = 'digraph {a -> b}';
class App extends Component {
setGraph() {
console.log('DOT source =', dotSrc);
d3.select(".graph").graphviz().renderDot(dotSrc);
}
render() {
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">Welcome to magjac's React hack</h1>
</header>
<script src="https://unpkg.com/viz.js#1.8.0/viz.js" type="javascript/worker"></script>
<div className="graph">
</div>
<button className="square" onClick={() => this.setGraph()}>
{'Click me'}
</button>
</div>
);
}
}
export default App;

Watching state from child component React with Material UI

New to React. Just using create-react-app and Material UI, nothing else.
Coming from an Angular background.
I cannot communicate from a sibling component to open the sidebar.
I'm separating each part into their own files.
I can get the open button in the Header to talk to the parent App, but cannot get the parent App to communicate with the child LeftSidebar.
Header Component
import React, {Component} from 'react';
import AppBar from 'material-ui/AppBar';
import IconButton from 'material-ui/IconButton';
import NavigationMenu from 'material-ui/svg-icons/navigation/menu';
class Header extends Component {
openLeftBar = () => {
// calls parent method
this.props.onOpenLeftBar();
}
render() {
return (
<AppBar iconElementLeft={
<IconButton onClick={this.openLeftBar}>
<NavigationMenu />
</IconButton>
}
/>
);
}
}
export default Header;
App Component -- receives event from Header, but unsure how to pass dynamic 'watcher' down to LeftSidebar Component
import React, { Component } from 'react';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import RaisedButton from 'material-ui/RaisedButton';
import Drawer from 'material-ui/Drawer';
import MenuItem from 'material-ui/MenuItem';
// components
import Header from './Header/Header';
import Body from './Body/Body';
import Footer from './Footer/Footer';
import LeftSidebar from './LeftSidebar/LeftSidebar';
class App extends Component {
constructor() {
super() // gives component context of this instead of parent this
this.state = {
leftBarOpen : false
}
}
notifyOpen = () => {
console.log('opened') // works
this.setState({leftBarOpen: true});
/*** need to pass down to child component and $watch somehow... ***/
}
render() {
return (
<MuiThemeProvider muiTheme={getMuiTheme(darkBaseTheme)}>
<div className="App">
<Header onOpenLeftBar={this.notifyOpen} />
<Body />
<LeftSidebar listenForOpen={this.state.leftBarOpen} />
<Footer />
</div>
</MuiThemeProvider>
);
}
}
export default App;
LeftSidebar Component - cannot get it to listen to parent App component - Angular would use $scope.$watch or $onChanges
// LeftSidebar
import React, { Component } from 'react';
import Drawer from 'material-ui/Drawer';
import MenuItem from 'material-ui/MenuItem';
import IconButton from 'material-ui/IconButton';
import NavigationClose from 'material-ui/svg-icons/navigation/close';
class LeftNavBar extends Component {
/** unsure if necessary here **/
constructor(props, state) {
super(props, state)
this.state = {
leftBarOpen : this.props.leftBarOpen
}
}
/** closing functionality works **/
close = () => {
this.setState({leftBarOpen: false});
}
render() {
return (
<Drawer open={this.state.leftBarOpen}>
<IconButton onClick={this.close}>
<NavigationClose />
</IconButton>
<MenuItem>Menu Item</MenuItem>
<MenuItem>Menu Item 2</MenuItem>
</Drawer>
);
}
}
export default LeftSidebar;
Free your mind of concepts like "watchers". In React there is only state and props. When a component's state changes via this.setState(..) it will update all of its children in render.
Your code is suffering from a typical anti-pattern of duplicating state. If both the header and the sibling components want to access or update the same piece of state, then they belong in a common ancestor (App, in your case) and no where else.
(some stuff removed / renamed for brevity)
class App extends Component {
// don't need `constructor` can just apply initial state here
state = { leftBarOpen: false }
// probably want 'toggle', but for demo purposes, have two methods
open = () => {
this.setState({ leftBarOpen: true })
}
close = () => {
this.setState({ leftBarOpen: false })
}
render() {
return (
<div className="App">
<Header onOpenLeftBar={this.open} />
<LeftSidebar
closeLeftBar={this.close}
leftBarOpen={this.state.leftBarOpen}
/>
</div>
)
}
}
Now Header and LeftSidebar do not need to be classes at all, and simply react to props, and call prop functions.
const LeftSideBar = props => (
<Drawer open={props.leftBarOpen}>
<IconButton onClick={props.closeLeftBar}>
<NavigationClose />
</IconButton>
</Drawer>
)
Now anytime the state in App changes, no matter who initiated the change, your LeftSideBar will react appropriately since it only knows the most recent props
Once you set the leftBarOpen prop as internal state of LeftNavBar you can't modify it externally anymore as you only read the prop in the constructor which only run once when the component initialize it self.
You can use the componentWillReceiveProps life cycle method and update the state respectively when a new prop is received.
That being said, i don't think a Drawer should be responsible for being closed or opened, but should be responsible on how it looks or what it does when its closed or opened.
A drawer can't close or open it self, same as a light-Ball can't turn it self on or off but a switch / button can and should.
Here is a small example to illustrate my point:
const LightBall = ({ on }) => {
return (
<div>{`The light is ${on ? 'On' : 'Off'}`}</div>
);
}
const MySwitch = ({ onClick, on }) => {
return (
<button onClick={onClick}>{`Turn the light ${!on ? 'On' : 'Off'}`}</button>
)
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
lightOn: false
};
}
toggleLight = () => this.setState({ lightOn: !this.state.lightOn });
render() {
const { lightOn } = this.state;
return (
<div>
<MySwitch onClick={this.toggleLight} on={lightOn} />
<LightBall on={lightOn} />
</div>
);
}
}
ReactDOM.render(<App />, 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>

Resources