Using method from parent component - javascript

Its possible to use a function from the parent component in a child component even if this function changes the parent state? (this function has a parameter)
How would i export it to my child component and use it?
This is the function i want to export and use in my child component:
function atualizarCadastros(novoCadastro){
setCadastros(cadastrosAtuais => {
return[...cadastrosAtuais, novoCadastro]
})
}
Parent component:
import './App.css';
import React, {useState} from 'react';
import {Table, Jumbotron, Button} from 'react-bootstrap'
import Formulario from './Formulario'
import renderCadastros from './renderCadastros'
function App() {
const [Cadastros, setCadastros] = useState([{
"id": 1,
"nome": "Francisca Julia da Costa",
"cpf": "457.696.936-65",
"rg": "47.360.897-2",
"data_nasc": "23/03/1944",
"sexo": "Feminino"
},
{
"id": 2,
"nome": "Noah Felipe Silva",
"cpf": "956.531.431-70",
"rg": "40.974.782-8",
"data_nasc": "11/07/1964",
"sexo": "Masculino"
},
{
"id": 3,
"nome": "Alícia Rosângela Melo",
"cpf": "066.291.353-18",
"rg": "36.214.141-1",
"data_nasc": "18/02/1978",
"sexo": "Feminino"
}])
function atualizarCadastros(novoCadastro){
setCadastros(cadastrosAtuais => {
return[...cadastrosAtuais, novoCadastro]
})
}
return (
<Jumbotron style={{background: 'transparent'}}>
<Formulario/>
<Table striped bordered hover size='sm'>
<thead>
<tr>
<th>id</th>
<th>Nome</th>
<th>CPF</th>
<th>RG</th>
<th>Nascimento</th>
<th>Sexo</th>
<th></th>
</tr>
</thead>
<tbody>
{Cadastros.map(renderCadastros)}
</tbody>
</Table>
</Jumbotron>
);
}
export default App;
Child component:
import './App.css';
import React, {useRef} from 'react';
import {Button, Form, Col} from 'react-bootstrap'
function Formulario (){
return(
<div>
<Form>
<Form.Row>
<Col>
<Form.Label>Identificação</Form.Label>
<Form.Control placeholder="Id" />
</Col>
<Col>
<Form.Label>Nome Completo</Form.Label>
<Form.Control placeholder="João Silva" />
</Col>
<Col>
<Form.Label>CPF</Form.Label>
<Form.Control placeholder="000.000.000-00" />
</Col>
<Col>
<Form.Label>RG</Form.Label>
<Form.Control placeholder="0.000.000" />
</Col>
<Col>
<Form.Label>Data de Nascimento</Form.Label>
<Form.Control placeholder="DD/MM/AAAA" />
</Col>
<Col>
<Form.Label>Sexo</Form.Label>
<Form.Control placeholder="Masculino/Feminino" />
</Col>
</Form.Row>
</Form>
<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center'}}>
<Button style={{margin: '10px'}} variant="primary">Cadastrar</Button>
</div>
</div>
)
}
export default Formulario
Thats other component from the application just so you can see it all:
import './App.css';
import React from 'react';
import {Button} from 'react-bootstrap'
function renderCadastros(cadastro, index){
return(
<tr id={cadastro.id} key={index}>
<td>{cadastro.id}</td>
<td contentEditable="true" suppressContentEditableWarning={true}>{cadastro.nome}</td>
<td contentEditable="true" suppressContentEditableWarning={true}>{cadastro.cpf}</td>
<td contentEditable="true" suppressContentEditableWarning={true}>{cadastro.rg}</td>
<td contentEditable="true" suppressContentEditableWarning={true}>{cadastro.data_nasc}</td>
<td contentEditable="true" suppressContentEditableWarning={true}>{cadastro.sexo}</td>
<td align="center"><Button variant="danger">Excluir</Button></td>
</tr>)
}
export default renderCadastros

You can pass functions down to child components via props, if the function alters state defined in the parent component, when that state has changed it React will re-render the parent and all its children.
import React from "react";
import "./styles.css";
export default function App() {
const [counter, setCounter] = React.useState(1);
const increment = (num) => {
setCounter(prev => prev + num)
}
return (
<div>
<div>Counter: {counter}</div>
<Child increment={increment}/>
</div>
);
}
function Child({increment}) {
handleClick() {
increment(1)
}
return (
<button onClick={handleClick}>Increment counter</button>
)
}

In your parent component you can pass down methods using props.
like this
//set your method to whatever you want to call it in your child component
<Formulario newFunction = {atualizarCadastros} />
then in your child component pass the prop at the top level like this
function Formulario ( {newFunction} ){
return(
<div>
<Form>
<Form.Row>
<Col>
<Form.Label>Identificação</Form.Label>
<Form.Control placeholder="Id" />
</Col>
<Col>
<Form.Label>Nome Completo</Form.Label>
<Form.Control placeholder="João Silva" />
</Col>
<Col>
<Form.Label>CPF</Form.Label>
<Form.Control placeholder="000.000.000-00" />
</Col>
<Col>
<Form.Label>RG</Form.Label>
<Form.Control placeholder="0.000.000" />
</Col>
<Col>
<Form.Label>Data de Nascimento</Form.Label>
<Form.Control placeholder="DD/MM/AAAA" />
</Col>
<Col>
<Form.Label>Sexo</Form.Label>
<Form.Control placeholder="Masculino/Feminino" />
</Col>
</Form.Row>
</Form>
<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center'}}>
<Button style={{margin: '10px'}} variant="primary">Cadastrar</Button>
</div>
</div>
)
}
export default Formulario
so whenever you want to call that function in your child just use newFunction. Hope this makes sense and helps!

You can pass the function as a prop to the child component.
Modify you map function to something like below
{Cadastros.map((item, index) => (
<renderCadastros
cadastro={item}
key={index}
atualizarCadastros={atualizarCadastros} />
)}
And you can consume the data and function in the child component as below
import './App.css';
import React from 'react';
import {Button} from 'react-bootstrap'
function renderCadastros({cadastro, atualizarCadastros}){
return(
<tr id={cadastro.id}>
<td>{cadastro.id}</td>
<td contentEditable="true" suppressContentEditableWarning={true}>{cadastro.nome}</td>
<td contentEditable="true" suppressContentEditableWarning={true}>{cadastro.cpf}</td>
<td contentEditable="true" suppressContentEditableWarning={true}>{cadastro.rg}</td>
<td contentEditable="true" suppressContentEditableWarning={true}>{cadastro.data_nasc}</td>
<td contentEditable="true" suppressContentEditableWarning={true}>{cadastro.sexo}</td>
<td align="center"><Button variant="danger">Excluir</Button></td>
</tr>)
}
export default renderCadastros
import './App.css';
import React, {useState} from 'react';
import {Table, Jumbotron, Button} from 'react-bootstrap'
import Formulario from './Formulario'
import renderCadastros from './renderCadastros'
function App() {
const [Cadastros, setCadastros] = useState([{
"id": 1,
"nome": "Francisca Julia da Costa",
"cpf": "457.696.936-65",
"rg": "47.360.897-2",
"data_nasc": "23/03/1944",
"sexo": "Feminino"
},
{
"id": 2,
"nome": "Noah Felipe Silva",
"cpf": "956.531.431-70",
"rg": "40.974.782-8",
"data_nasc": "11/07/1964",
"sexo": "Masculino"
},
{
"id": 3,
"nome": "Alícia Rosângela Melo",
"cpf": "066.291.353-18",
"rg": "36.214.141-1",
"data_nasc": "18/02/1978",
"sexo": "Feminino"
}])
function atualizarCadastros(novoCadastro){
setCadastros(cadastrosAtuais => {
return[...cadastrosAtuais, novoCadastro]
})
}
return (
<Jumbotron style={{background: 'transparent'}}>
<Formulario/>
<Table striped bordered hover size='sm'>
<thead>
<tr>
<th>id</th>
<th>Nome</th>
<th>CPF</th>
<th>RG</th>
<th>Nascimento</th>
<th>Sexo</th>
<th></th>
</tr>
</thead>
<tbody>
{Cadastros.map((item, index) => (
<renderCadastros cadastro={item} key={index} atualizarCadastros={atualizarCadastros} />
)}
</tbody>
</Table>
</Jumbotron>
);
}
export default App;

You can pass your function through props from the parent to child component. Reference as follows
Parent Component:
replace <Formulario /> with <Formulario atualizarCadastros={() => this. atualizarCadastros}
Arrow function used to bind.
Child Component:
to access the function
function Formulario (props) {
props.atualizarCadastros() // function call anywhere required
}

Related

Database API search and show result in List (React Native)

export class Diet extends Component {
render() {
return (
<SearchBar/>
<List>
<TouchableOpacity>
<Text>Foods</Text>
</TouchableOpacity>
</List>
)}}
Hey everyone, I can't figure out the following: I am trying to search foods from the database Edamam API by the SearchBar and list them in the List, this is the link of the page: https://developer.edamam.com/food-database-api-docs how can I do this?
Using Axios you can use your API url and using the state you can store the data and use it.
import React, {Component} from 'react';
import {Button, Card, CardBody, Col, Input, Modal, ModalBody, ModalFooter, ModalHeader, Row, Table} from "reactstrap";
import axios from 'axios';
import {FormGroup} from "react-bootstrap";
import InputColor from "react-input-color";
class labelx extends Component {
state = {
labels: []
}
componentWillMount() {
axios.get('http://APIURL').then(response => {
this.setState({
labels: response.data.data
})
}).then(console.log(this.state))
;
}
render() {
let projects = this.state.labels.map((book) => {
return (
<tr key={book.id}>
<td>{book.name}
</td>
<td style={{backgroundColor: book.color}}>{book.color}</td>
<td>
<Button color="danger" onClick={this.deleteProperty.bind(this, book.id)}>Delete</Button>
</td>
</tr>
)
});
return (
<>
<div className="content">
<Row>
<Col md="12">
<Card>
<CardBody>
<div className="content">
<div className="card-header">
<Table>
<thead>
<tr>
<th>name</th>
<th>color</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{projects}
</tbody>
</Table>
</div>
</div>
</CardBody>
</Card>
</Col>
</Row>
</div>
</>
);
}
}
export default labelx;

React Component Not Rendering the content

React router not rendering my JSX. The initial page renders the content inside. When I click add employee it doesn't display the content of the components. It renders a blank page. I'm a beginner in React.
CreateEmployeeComponent.jsx renders a blank page.
Below is the code of each file. Thanks in advance
App.js
import './App.css';
import React from 'react';
import ListEmployeeComponent from './components/ListEmployeeComponent';
import CreateEmployeeComponent from './components/CreateEmployeeComponent';
import HeaderComponent from './components/HeaderComponent';
import FooterComponent from './components/FooterComponent';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
function App() {
return (
<div>
<Router>
<div>
<HeaderComponent />
<div className="container">
<Switch>
<Route path="/" exact component={ListEmployeeComponent}></Route>
<Route path="/employees" component={ListEmployeeComponent}></Route>
<Route path="/add-emplyee" component={CreateEmployeeComponent}></Route>
</Switch>
</div>
<FooterComponent />
</div>
</Router>
</div>
);
}
export default App;
ListEmployeeComponent
import React, { Component } from 'react';
import EmployeeService from '../services/EmployeeService';
class ListEmployeeComponent extends Component {
constructor(props) {
super(props)
this.state = {
employees: []
}
this.addEmployee = this.addEmployee.bind(this);
}
componentDidMount() {
EmployeeService.getEmployees().then((res) => {
this.setState({ employees: res.data });
})
}
addEmployee() {
this.props.history.push('/add-employee');
}
render() {
return (
<div>
<h2 className="text-center">Employees List</h2>
<div className="row">
<button className="btn btn-primary" onClick={this.addEmployee}>Add Employee</button>
</div>
<div className="row">
<table className="table table-striped table-bordered">
<thead>
<tr>
<th>Employee First Name</th>
<th>Employee Last Name</th>
<th>Employee Email Id</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{
this.state.employees.map(
employee =>
<tr key={employee.id}>
<td> {employee.firstName} </td>
<td> {employee.lastName} </td>
<td> {employee.emailId} </td>
</tr>
)
}
</tbody>
</table>
</div>
</div>
);
}
}
export default ListEmployeeComponent;
CreateEmployeeComponent
import React, { Component } from 'react';
class CreateEmployeeComponent extends Component {
render() {
return (
<div>
<h1>Create Employee...</h1>
</div>
);
}
}
export default CreateEmployeeComponent;
You got type mistake : /add-emplyee -> /add-employee.
<Route path="/add-emplyee" component={CreateEmployeeComponent}></Route>
Please check it first

How do I populate a form field with data from redux?

I am having trouble trying to dynamically populate my "client edit form" with data from the corresponding listing in my "client table". As you can see, I have tried using "{this.onChange}", but to no avail.
import React, { Component } from "react";
import { Table, Container, Button } from "reactstrap";
import {
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input,
Card,
CardTitle,
CardText,
CardDeck,
CardSubtitle,
CardBody,
} from "reactstrap";
import { connect } from "react-redux";
import { getClients, addClient, deleteClient } from "../actions/clientActions";
import PropTypes from "prop-types";
class ClientTable extends Component {
componentDidMount() {
this.props.getClients();
}
state = {
detailModal: false,
editModal: false,
name: "",
email: "",
number: "",
};
toggleEdit = () => {
this.setState({
editModal: !this.state.editModal,
});
};
toggleDetails = () => {
this.setState({
detailModal: !this.state.detailModal,
});
};
onDeleteClick = (id) => {
this.props.deleteClient(id);
};
renderClient = (clients, _id) => {
return (
<tr key={_id} timeout={500} classNames="fade">
<td>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => this.onDeleteClick(clients._id)}
>
×
</Button>
<Button
style={{ marginLeft: ".2rem" }}
className="add-btn"
outline
color="warning"
size="sm"
onClick={this.toggleEdit}
>
Edit
</Button>
<Button
style={{ marginLeft: ".3rem" }}
className="detail-btn"
outline
color="info"
size="sm"
onClick={this.toggleDetails}
>
Details
</Button>
</td>
<td>{clients.name}</td>
<td>{clients.email}</td>
<td>{clients.number}</td>
</tr>
);
};
render() {
const { clients } = this.props.client;
return (
<Container id="listContainer">
<Table
id="listTable"
className="table-striped table-bordered table-hover"
dark
>
<tr class="listRow">
<thead id="tableHeader">
<tr>
<th id="listActions">Actions</th>
<th id="listName">Name</th>
<th id="listEmail">Email</th>
<th id="listNumber">Number</th>
</tr>
</thead>
<tbody class="listRow">{clients.map(this.renderClient)}</tbody>
</tr>
<Modal isOpen={this.state.editModal} toggle={this.toggleEdit}>
<ModalHeader toggle={this.toggleEdit}> Edit Client </ModalHeader>
<ModalBody>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<Label for="name"> Name </Label>
<Input
type="text"
name="name"
id="client"
placeholder="Add name"
onChange={this.onChange}
></Input>
<Label for="email"> Email </Label>
<Input
type="text"
name="email"
id="client"
placeholder="Add email"
onChange={this.onChange}
></Input>
<Label for="number"> Number </Label>
<Input
type="text"
name="number"
id="number"
placeholder="Add number"
onChange={this.onChange}
></Input>
<Button color="dark" style={{ marginTop: "2rem" }} block>
Submit Client Edit
</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
<Modal isOpen={this.state.detailModal} toggle={this.toggleDetails}>
<ModalHeader toggle={this.toggleDetails}>
Client Details
</ModalHeader>
<CardDeck>
<Card></Card>
</CardDeck>
</Modal>
</Table>
</Container>
);
}
}
ClientTable.propTypes = {
getClients: PropTypes.func.isRequired,
client: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
client: state.client,
});
export default connect(mapStateToProps, {
getClients,
deleteClient,
addClient,
})(ClientTable);
How would I go about putting data from the redux store into the fields in my "Edit Client" form? If anyone has any ideas I would greatly appreciate it. This one is stumping me.
In general, by "controlling" the "value" property of an element. Instead of the element taking care of updating its displayed value natively - and triggering handlers only incidentally to what is visible - its value is passed in as the value from the store. The element then sets its value indirectly, through the reducer and store.
Clarification: the value of an html input element can be controlled using the jsx "value" prop. Pass in an onChange function (which you're already doing) and a value prop to create a typical controlled component.
<input value={state} onChange={onChange} />
https://reactjs.org/docs/forms.html#controlled-components

How can I have a button in one component that renders another separate component?

I am trying to create an 'edit' button inside of component with an onClick that renders a separate component that is a 'client edit modal'. I'm having trouble figuring out how to do this.
Component with the 'edit' button
import React, { Component } from "react";
import { Table, Container, Button } from "reactstrap";
import {
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input,
} from "reactstrap";
import { connect } from "react-redux";
import {
getClients,
addClient,
editClient,
deleteClient,
} from "../actions/clientActions";
import PropTypes from "prop-types";
class ClientTable extends Component {
componentDidMount() {
this.props.getClients();
}
renderClient = (clients, _id) => {
return (
<tr key={_id} timeout={500} classNames="fade">
<td>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => this.onDeleteClick(clients._id)}
>
×
</Button>
<Button
style={{ marginLeft: ".3rem" }}
className="add-btn"
outline
color="warning"
size="sm"
>
Edit
</Button>
<Button
style={{ marginLeft: ".3rem" }}
className="detail-btn"
outline
color="info"
size="sm"
>
Details
</Button>
</td>
<td>{clients.name}</td>
<td>{clients.email}</td>
<td>{clients.number}</td>
</tr>
);
};
onDeleteClick = (id) => {
this.props.deleteClient(id);
};
render() {
const { clients } = this.props.client;
return (
<Container id="listContainer">
<Table
id="listTable"
className="table-striped table-bordered table-hover"
dark
>
<tr class="listRow">
<thead id="tableHeader">
<tr>
<th id="listActions">Actions</th>
<th id="listName">Name</th>
<th id="listEmail">Email</th>
<th id="listNumber">Number</th>
</tr>
</thead>
<tbody class="listRow">{clients.map(this.renderClient)}</tbody>
</tr>
</Table>
</Container>
);
}
}
ClientTable.propTypes = {
getClients: PropTypes.func.isRequired,
client: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
client: state.client,
});
export default connect(mapStateToProps, {
getClients,
deleteClient,
addClient,
})(ClientTable);
Component that button will render
import React, { Component } from "react";
import {
Button,
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input,
} from "reactstrap";
import { connect } from "react-redux";
import { editClient } from "../actions/clientActions";
import { CLIENTS_LOADING } from "../actions/types";
class ClientEditModal extends Component {
state = {
modal: false,
name: "",
email: "",
number: "",
};
toggle = () => {
this.setState({
modal: !this.state.modal,
});
};
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = (e) => {
e.preventDefault();
const editClient = {
name: this.state.name,
email: this.state.email,
number: this.state.number,
};
this.props.editClient(editClient);
this.toggle();
};
render() {
return (
<div>
<Modal isOpen={this.state.modal} toggle={this.toggle}>
<ModalHeader toggle={this.toggle}> Edit Client</ModalHeader>
<ModalBody>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<Label for="name"> Name </Label>
<Input
type="text"
name="name"
id="client"
placeholder="Add name"
onChange={this.onChange}
></Input>
<Label for="email"> Email </Label>
<Input
type="text"
name="email"
id="client"
placeholder="Add email"
onChange={this.onChange}
></Input>
<Label for="number"> Number </Label>
<Input
type="text"
name="number"
id="client"
placeholder="Add number"
onChange={this.onChange}
></Input>
<Button color="dark" style={{ marginTop: "2rem" }} block>
Submit Changes
</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
const mapStateToProps = (state) => ({
client: state.client,
});
export default connect(mapStateToProps, { editClient })(ClientEditModal);
I also would like to do the same for the 'details' button, but I assume that would be rather simple once I figure out how to do it once. If anyone has any ideas I would be very grateful! Thank you
You can do something like this:
class ClientEditModal extends Component {
//...
componentDidMount() {
if (this.props.isOpen) {
this.toggle(true);
}
}
toggle = (isOpen) => {
this.setState({
modal: isOpen,
});
}
// ...
}
and in your ClientTable, create a new state isOpen that you flip when you press the edit button.
showModal = () => {
this.setState({ isOpen: true; });
}
//...
<Button onClick={this.showModal}>Edit</Button>
Then pass the isOpen state to the ClientEditModal
<ClientEditModal isOpen={this.state.isOpen} {...otherProps} />

React-Bootstrap grid contents not displaying

I created a grid inside of a react-bootstrap Jumbotron, but when I export it to my app.jsx none of the grid contents are displayed (but the Jumbotron and my custom styles are)
All of my other components are working fine, so I'm not sure why this isn't.
App.js:
import React, { Component } from 'react';
import {Grid} from 'react-bootstrap';
import {Row} from 'react-bootstrap';
import {Col} from 'react-bootstrap';
import MyNavbar from './modules/MyNavbar.jsx';
import SectionOne from './modules/SectionOne.jsx'
import SectionTwo from './modules/SectionTwo.jsx'
import SectionThree from './modules/SectionThree.jsx';
class App extends Component {
render() {
return (
<div className="App">
<MyNavbar/>
<SectionOne/>
<SectionTwo/>
<SectionThree/>
</div>
);
}
}
export default App;
SectionThree.jsx:
import React, { Component } from 'react';
import {Jumbotron} from 'react-bootstrap';
import howItWorks from './howItWorks.jsx';
class SectionThree extends Component {
render() {
return(
<Jumbotron id="jumbotronThree">
<howItWorks/>
</Jumbotron>
)
}
}
export default SectionThree;
howItWorks.jsx:
import React, { Component } from 'react';
import {Image} from 'react-bootstrap';
import {Grid} from 'react-bootstrap';
import {Col} from 'react-bootstrap';
import {Row} from 'react-bootstrap';
class howItWorks extends Component {
render() {
return(
<div>
<Grid fluid>
<Row>
<Col md={4}>
<div className="searchIcon">
<Image src="http://imgur.com/KgAIBCc.jpg" responsive/>
</div>
</Col>
<Col md={4}>
<div className="payIcon">
<Image src="http://imgur.com/KgAIBCc.jpg" responsive/>
</div>
</Col>
<Col md={4}>
<div className="eatIcon">
<Image src="http://imgur.com/KgAIBCc.jpg" responsive/>
</div>
</Col>
</Row>
<Row>
<Col md={4}>
<p>
test
</p>
</Col>
<Col md={4}>
<p>
test
</p>
</Col>
<Col md={4}>
<p>
test
</p>
</Col>
</Row>
</Grid>
</div>
)
}
}
export default howItWorks;
React components should always start with uppercase letter:
class HowItWorks extends Component {
render() {
...
<Jumbotron id="jumbotronThree">
<HowItWorks/>
...
There is a good answer on stackoverflow here covering this.
The Component Grid is now calling as Container. Type Container instead of Grid in the react js code.

Categories

Resources