Accessing the data from one component to another component - javascript

Hi I am starting to learn reactjs. So after understanding the basics Im starting to work on database connectivity using reactjs. In the code Im trying to get the userId and Password to establish a DB connectivity and trying to list the tables available in the DB. In the Login.js I have create a form (userId and Password) when login button is clicked I will make a connectivity and execute the Show Table query to list all the tables in the DB, and move to the Table.js page where I try to list the available tables. Right now I able to connect to the DB but not able to display the tables in the Table.js, so how to display the tables list in the Table.js file, because I have placed my DB connectivity and query inside a button event in the Login.js. Also Is there a possible to declare a variable global and access it across the another js files. Any help would be great, thank you.
Login.js
import React from 'react';
import TableContent from './tables';
class Login extends React.Component{
constructor(){
super();
this.state={
showComponent : false,
};
// this.buttonClick = this.buttonClick.bind(this);
}
buttonClick(event){
event.preventDefault();
this.setState({
showComponent: true,
})
var db = require('#dataBase/dynamoConnect')({
"UserId": "XXXXXXXXXXXXXXXXXXXXXXXX",
"Password": "YYYYYYYYYYYYYYY",
"region": "ZZZZZZZZZZ"
});
db.query("SHOW TABLES",(err,data)=>{
const tableList = data;
console.log(tableList);
})
}
render(){
return(
<div>
<form>
<label>User Id :</label>
<input type="text" className="test"/>
<br/>
<label>Password :</label>
<input type="text" className="test" />
<button onClick={this.buttonClick.bind(this)} className="connect" > Login</button>
</form>
{this.state.showComponent && <TableContent />}
</div>
)
}
}
export default Login;
Table.js
import React from 'react';
class TableContent extends React.Component {
constructor() {
super();
this.state = {
showComponent: false,
};
this.buttonClick = this.buttonClick.bind(this);
}
buttonClick(event) {
event.preventDefault();
this.setState({
showComponent: true,
})
}
render() {
return (
<div>
<form>
<div id="first">
<label> Table </label>
<br />
//Display the tables from DB here
<select name="sometext" multiple="multiple" >
<option>Table1</option>
<option>Table2</option>
<option>Table3</option>
<option>Table4</option>
<option>Table5</option>
</select>
</div>
<div id="second">
<label> SQL </label>
<br/>
<textarea rows="4" cols="50">SQL </textarea>
</div>
<button onClick={this.buttonClick.bind(this)} > Execute </button>
<div id="third" >
{this.state.showComponent && <SampleTable />}
</div>
</form>
</div>
)
}
}
export default TableContent;

First.
The Table.js component need to know the data to display.
1 - you have to save result of the query in component state, by calling this.setState({tableData: tableList}) in query callback:
db.query("SHOW TABLES",(err,data)=>{
const tableList = data;
this.setState({
tableData: tableList,
});
})
2 - you need to pass saved result as a property to TableContent, like this:
in Login.js:
{this.state.showComponent && <TableContent data={this.state.tableData} />};
3 - render data in the child component. You can get access to it via this.props.data. You can iterate over an result array and render all table rows in single loop. Take a look at this react doc.
Second:
Also Is there a possible to declare a variable global and access it across the another js files
In short - yes. You can export functions, variables, classess from your module.
Small example:
// scriptA.js;
export const a = 42;
// scriptB.js;
import { a } from 'path/to/scriptA.js';
console.log(a) // will print 42;
This example assumes you are using es6 import/export feature. You can require it as well.

There are a number of strategies for communicating between components, but the easiest way (without using Flux or Redux) is to use a parent component to act as a mediator for the communication.
Basically, the parent passes a callback to one component that sets some state to pass down the the other component, for example:
Child creating data
class Child1 extends React.Component {
constructor() {
super()
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.props.setMessage("hello world")
}
render() {
return <button onClick={this.handleClick}>say hello</button>
}
}
Child using data
const Child2 = ({message}) => {
return <p>{message}</p>
}
Parent
class Parent extends React.Component {
constructor() {
super()
this.state = { message: "" }
}
render() {
return (
<div>
<Child1 setMessage={(message) => this.setState({ message })} />
<Child2 message={this.state.message} />
</div>
)
}
}
If they can't be siblings, this pattern can get a bit strenuous, but can still be achieved by having the mediator component as the lowest common ancestor and passing the relevant props all the way down. At that point though, you may want to investigate Flux or Redux and externalising the state from the components entirely.

Related

React : Pass conditional renderings data

Assuming that this is a Toggle component to hide and display data, when called alone it's working perfectly.
Now I have a dashboard.js where I will be calling this component, but I only want to output the data, keeping the toggle switch separated in his file.
How do I pass data from the Toggle component to the Dashboard component ?
Still newbie in React and from what I learned apparently you can't pass data from child to parent.
import React, { Component } from 'react';
export default class Toggle extends React.Component{
constructor(){
super();
this.state={isShowBody: false}
}
handleClick(event) {
this.setState({isShowBody: !this.state.isShowBody})
}
render() {
return (
<div >
<div >
<span className="switch switch-sm" >
<label>
<input type="checkbox" name="select" onClick={this.handleClick.bind(this)}/>
<span />
</label>
</span>
</div>
{this.state.isShowBody ?
<div>
Data test
</div>
: null}
</div>
);
}
}
This might give you more insight in addition to what the previous answer is: Using Redux would definitely a good option but that entirely depends on the complexity of the project.
export class Toggle extends React.Component {
constructor(){
super();
this.state={
isShowBody: false
}
}
handleClick = (event) => {
this.setState({ isShowBody: !this.state.isShowBody })
}
checkbox = () => {
return (
<span className="switch switch-sm" >
<label>
<input type="checkbox" name="select" onClick={() => this.handleClick(this)}/>
</label>
</span>
)
}
dataTest = () => {
return (
<div>
Data test
</div>
)
}
render() {
return (
<div>
{this.checkbox()}
{this.state.isShowBody && this.dataTest()}
/**
* You can extract this dataSet into another component as well where you can pass initial visibility value as this.state.isShowBody
* for example
* <Dataset visibility={this.state.isShowBody} />
* */
</div>
);
}
}
If you want the parent to have information the child has you need to left up the state to the parent component and pass it to the child.
If your component has the potential to become bigger, keeping lifting up the state will become a problem so consider using a state management library like Redux.

React passing fetched data to another component

Hy!
I am having an issue with my react code. My task is to call from iTunes API which i do with fetch then I process the data. But I cannot save it as a variable to be able to pass it around later.
import React, { Component } from 'react';
class SearchField extends Component{
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange = (event) => {
this.setState({value: event.target.value});
}
handleSubmit = (event) => {
event.preventDefault();
fetch(`https://itunes.apple.com/search?media=music&term=${this.state.value.toLowerCase()}`)
.then((resp) => resp.json())
.then(searchRes => searchRes.results[0].artistName)
.catch(err => console.log(err));
}
render() {
return(
<section className="hero is-primary">
<div className="hero-body">
<div className="container">
<form onSubmit={this.handleSubmit}>
<input className="input is-primary" type="text" value={this.state.value} onChange={this.handleChange} placeholder="Search for artist" />
<input className="button is-info" type="submit" value="Search" />
</form>
</div>
</div>
</section>
)
}
}
export default SearchField;
I'd have to use the fetched data later, i just need the artist name first.
If I log the value (searchRes.results[0].artistName, i get the correct value, but if i want to save it for later use i only got empty console.log back.
I've tried several approaches but I never get my result back.
Help me out please.
Remember that data flow in React is unidirectional. If you want to share the data around your app the search component should not be the component that fetches the data. That should be left to a parent component (maybe App). That component should have a function that handles the fetch request, and you can then pass a reference to that function down to the search component to call when the button is clicked. Then, once that data is loaded, the parent (App) component can pass all the relevant data down to the child components.
Here's a quick mock-up based on your existing code:
class Search extends {
constructor(props) {
super(props);
this.state = { url: '' };
this.handleKey = this.handleKey.bind(this);
}
handleKey(e) {
const url = e.target.value;
this.setState({ url });
}
render() {
const { url } = this.state;
// grab the function passed down from App
const { fetchData } = this.props;
return (
<input onKeyUp={this.handleKey} value={url} />
// Call that function with the url when the button is clicked
<button onClick={() => fetchData(url)}>Click</button>
)
}
}
class App extends Component {
constructor(props) {
super(props);
this.state = { data: [] };
this.fetchData = this.fetchData.bind(this);
}
// App contains the fetch method
fetchData(url) {
fetch(url)
.then(res => res.json())
// Update the App state with the new data
.then(data => this.setState({ data });
}
render() {
const { data } = this.state;
// Sanity check - if the state is still empty of data, present
// a loading icon or something
if (!data.length) return <Spinner />
// otherwise return the rest of the app components
// passing in the fetch method as a prop for the search component
return (
<OtherComponent data={data} />
<Search fetchData={this.fetchData} />
)
}
}
Please specify what you mean by
but if i want to save it for later use i only got empty console.log back
I think the correct way to handle your problem is by passing a callback function to your component's props that gets called whenever you press search and a search result is found, like this: https://codesandbox.io/s/xpq171n1vz
Edit: Note that while this answer has been accepted and is a way to solve your problem, Andy's answer contains solid and elaborate advice on how to actually structure your components.

How can a component send a message to its sibling without moving the state up the component tree?

I've got a "page" component which houses a form and a list. The form and the list are completely self-contained and disjoint except for the fact that when you save the form, the list should refresh.
My page component looks like this, in its entirety:
export default class PaymentsPage extends React.PureComponent {
static propTypes = {
bookingId: XPropTypes.stringOrNumber.isRequired,
test: PropTypes.bool,
stripePublishableKey: PropTypes.string,
stripeUserId: PropTypes.string,
};
render() {
return (
<div>
<ContentSection title="Enter Payment" storageKey="record-payment">
<RecordPaymentForm bookingId={this.props.bookingId} test={this.props.test} />
</ContentSection>
<ContentSection title="Previous Payments" storageKey="previous-payments">
<PreviousPaymentsTable bookingId={this.props.bookingId} test={this.props.test} stripePublishableKey={this.props.stripePublishableKey} stripeUserId={this.props.stripeUserId} />
</ContentSection>
</div>
)
}
}
My question is, how can RecordPaymentForm send a message to PreviousPaymentsTable to tell it to refresh?
I don't want to move RecordPaymentForm's state up into PaymentsPage because I want it to remain self-contained.
I'm not using flux/redux, nor do I plan on it right now.
Using mufa (event oriented programming), communication among siblings will be as following :
Component Sender (Publisher) :
import {fire} from 'mufa';
class RecordPaymentForm extends React.Component {
// Assuming that the trigger to send the message is the following
handleClick() {
const message = 'this is a message from RecordPaymentForm';
fire('sendSomething', message);
}
}
Component Receiver (Subscriber) :
import {on} from 'mufa';
class PreviousPaymentsTable extends React.Component {
componentDidMount() {
on('sendSomething', (message) => {
this.setState({recordPaymenetMessage: message});
})
}
}
//if your are using npm => import {on, fire} from 'mufa';
const {on, fire} = window.mufa;
class RecordPaymentForm extends React.Component {
onClick(event) {
fire('addPayment', this.refs.item.value, this.refs.price.value);
}
render() {
return (
<div>
<input ref="item" placeholder="item name" />
<input ref="price" placeholder="price" type="number" />
<button onClick={this.onClick.bind(this)}>Add</button>
</div>
)
}
}
class PreviousPaymentsTable extends React.Component {
state={records:[]}
componentDidMount() {
on('addPayment', (item, price) => {
this.setState({records: [...this.state.records, {item, price}]});
})
}
render() {
return (
<ul>
{
this.state.records.map((r, index) =>
<li key={index}> <b> {r.item} : </b> {r.price} $ </li>)
}
</ul>
)
}
}
class App extends React.Component {
render() {
return (
<div>
<RecordPaymentForm />
<PreviousPaymentsTable />
</div>
)
}
}
ReactDOM.render(<App />, document.querySelector('section'))
<script src="https://cdn.rawgit.com/abdennour/mufa/ddf78fd9/cdn/mufa-latest.min.js"></script>
<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>
<section />
General Rules for React with Event-driven :
publish (fire) : is called in events handlers.
subscribe (on) : is called in componentDidMount.
unsubscribe (off) : is called in componentWillUnmount
I don't want to move RecordPaymentForm's state up into PaymentsPage because I want it to remain self-contained.
To your point above, RecordPaymentForm isn't self contained if you want it to update another component.
The proper "React" way to handle this situation is to store the shared state for both RecordPaymentForm and PreviousPaymentsTable in the parent component (PaymentsPage) and pass it into each child component.
To update the state of PaymentsPage from RecordPaymentForm, you can pass a function as a prop to act as a handler. and you can create the handleChange function in PaymentsPage.
export default class PaymentsPage extends React.PureComponent {
static propTypes = {
bookingId: XPropTypes.stringOrNumber.isRequired,
test: PropTypes.bool,
stripePublishableKey: PropTypes.string,
stripeUserId: PropTypes.string,
};
handleChange(newValue) => {
this.setState({
someProp: newValue;
});
}
render() {
return (
<div>
<ContentSection title="Enter Payment" storageKey="record-payment">
<RecordPaymentForm
bookingId={this.props.bookingId}
onChange={this.handleChange}
someProp={this.props.someProp}
test={this.props.test}
/>
</ContentSection>
<ContentSection title="Previous Payments" storageKey="previous-payments">
<PreviousPaymentsTable
bookingId={this.props.bookingId}
test={this.props.test}
someProp={this.props.someProp}
stripePublishableKey={this.props.stripePublishableKey}
stripeUserId={this.props.stripeUserId}
/>
</ContentSection>
</div>
)
}
}
I just implemented PubSubJS in about 3 lines of code. I think it will work well for this particular use-case.
When a payment is entered, I publish a "paymentEntered" event. Any component that's interested (such as my PreviousPaymentsTable) can subscribe to that topic, and then do what it needs to.
More-over, I could even publish the payment data and pop it into my payments list so that I don't have to do a full refresh, but I'm going to anyway because I already have the code for it and I don't mind a 50ms delay for fresh data.
This way my payments page remains dumb, and I can move these components around to any page, and re-use them where ever I please, with or without each-other, and they'll continue to work.

Programmatically open a route with state in react

I have two types of item, one of which can contain data similar to the other.
Currently when form is used to save an item it saves it then uses browserHistory.push to show the next page.
But I wish add a button that will
save the currently item
redirect them to the form to add the other item type,
partially fill out this form with the data from the first item.
Is there a way to do this using react and not using local storage or session variables?
You should take a look to Redux (or other Flux based libraries) to store data between components and routes, avoiding the excessive prop nesting.
browserHistory.push won't work. It only moves you to a certain location but it doesn't update the application state. You need to update application state, which then will reflect into location update, but not in the opposite direction. Keep in mind that, in React, data comes first, and its representation, even though mutable, doesn't change the data back. The same applies to the location.
To make the redirect alone work, I'd recommend wrapping your component into withRouter higher-order component.
import React, { Component } from 'react';
import { withRouter } from 'react-router';
class MyComponent extends Component {
render() {
return (
<div>
<button
onClick={() => this.props.router.push('/new-location')}>
Click me to go to /new-location
</button>
</div>
);
}
}
But if you need to pass data from one component to another, and the two aren't in hierarchy, I'd agree with Alomsimoy and recommend using Redux. But if, for some reason, it's not an option, you can store this data in a component that is parent to both forms:
class FormA extends Component {
render() {
return (
<form onSubmit={() => this.props.onSubmit()}>
<input
type="text"
value={this.props.inputA}
onChange={(event) => this.props.handleChangeA(event)} />
</form>
);
}
}
class FormB extends Component {
render() {
return (
<form onSubmit={() => this.props.onSubmit()}>
<input
type="text"
value={this.props.inputB}
onChange={(event) => this.props.handleChangeB(event)} />
</form>
);
}
}
while their parent would rule the location and state updates:
class Forms extends Component {
constructor() {
super();
this.state = {};
}
handleChange(name, value) {
this.setState({
[name]: value
});
}
renderForm() {
const {
params: {
stepId
}
} = this.props;
if (stepId === 'step-a') { // <- will be returned for location /form/step-a
return (
<FormA
inputA={this.state.inputA}
handleChangeA={(event) => this.handleChange('inputA', event.target.value)}
onSubmit={() => this.props.router.push('/form/step-b')} />
);
} else if (stepId === 'step-b') { // <- will be returned for location /form/step-b
return (
<FormB
inputB={this.state.inputB}
handleChangeB={{(event) => this.handleChange('inputA', event.target.value)} />
);
}
}
render() {
const {
children
} = this.props;
console.log(this.state); // track changes
return (
<div>
{this.renderForm()}
<button
onClick={() => this.props.router.push('/new-location')}>
Click me to go to /new-location
</button>
</div>
);
}
}
export default withRouter(Forms);
so the route for them would look like
<Route path="form/:stepId" component={Forms} />

onclick show and hide data in react.js

i have component which is showing data in the webpage
I want to write another component and create buutton in it. which just hide other component on clicking the button and show basic input field form.
My code is something like this
component app
class App extends React.Component{
constructor(props) {
super(props);
this.state= {
filter: null,
};
this.setFilter = this.setFilter.bind(this);
}
setFilter(filter) {
this.setState({filter: filter})
}
render(){
let filteredPassword = details_data.filter(
(detail) =>{
console.log(detail.website.toLowerCase(), this.state.filter)
return detail.website.toLowerCase().indexOf(this.state.filter)!= -1;
}
);
return (
<ul>
<Filter onUpdateFilter={this.setFilter} />
{
filteredPassword.map((detail)=>{
return <Detail item={detail}
key={detail.id}/>
})
}
</ul>
)
}
}
Another Detail component
class Filter extends React.Component{
constructor() {
super();
this.state={
search: 'Search'
}
}
updateSearch(event) {
this.props.onUpdateFilter(event.target.value.substr(0,40))
}
formShow(){
}
render() {
return (
<div>
<input id="search" type="text" placeholder={this.state.search} onChange={this.updateSearch.bind(this)}/>
<input id="button1" type="button" value="+" onClick={this.formShow()}/>
</div>
)
}
}
Few other component like this.
i am trying to hide the table and form button above is used to "show form" button.
class Form extends React.Component {
render() {
return(
<div>
<form>
<input type="text" placeholder="username" />
<input type="password" placeholder="username" />
</form>
</div>
)
}
}
Guide me how to do this.. thank you
Without looking too much to your code (it's a bit messy) it seems to me what you want to achieve is to communicate two components. Component A will react to a button click event and tell: 1) component B to hide and 2) component C to show up.
The way of doing this depends on if the components have hierarchical relationship or not. I would recommend start by reading this chapter of the official React documentation. Then, here is also a great article on component communication strategies in React.
On top of that, some patterns that focus specifically on this have achieved great success, like Flux or Redux.
Hope it helps.

Categories

Resources