React update s stateless component from another compoent - reactjs

export default function App() { return(<div><customButton/><customTable/></div>) }
export default function customButton() { return(<div><button>update</button></div>) }
Since the app is the parent component and button and table are child components. I know this is not the best practice but how do I update(re-render) table component from the button component?

The way to do this would be to have some shared state at the closest ancestor. In the example below, I create a value state variable in App and pass it to the customTable element. I have a setValue setter that is passed to customButton. When the button is clicked, the value is updated and passed to customTable, causing the table to re-render with that new value.
export default function App() {
const [value, setValue] = React.useState(0);
return(
<div>
<customButton setValue={setValue} />
<customTable value={value} />
</div>
)
}
export default function customButton({ setValue }) {
return(
<div>
<button onClick={() => setValue(v => v + 1)}>update</button>
</div>
)
}

Sample application using custom table and custom button.
function CustomButton(props) {
return <button onClick={props.addClick}>{props.children}</button>
}
function CustomTable({ table }) {
return (
<table>
<thead>
<tr>
<th>No.</th>
<th>Name</th>
</tr>
</thead>
<tbody>
{table.map((item, i) => (
<tr key={i.toString()}>
<td>{i.toString()}</td>
<td>{item.name}</td>
</tr>
))}
</tbody>
</table>
);
}
function App() {
const [input, setInput] = React.useState('')
const [table, setTable] = React.useState([
{ name: "John" },
{ name: "Bukky" },
{ name: "Behem" }
]);
const handleInput = e=>{
setInput(e.target.value)
}
const addClick = e => {
const update = [...table, { name: input }];
setTable(update);
setInput('')
};
return (
<div>
<input type="text" value={input} onChange={handleInput}/>
<CustomButton addClick={addClick}>Click to Add</CustomButton>
<CustomTable table={table} />
</div>
);
}

Related

refreshing react component after navigation doesn't work

refreshing react component after navigation
I wanted to refresh my component, which has a table . After navigating to that page but nothing happened since the useeffect doesn't work.
Actually, there is a delete button ,once click on it it should remove some data and redirect to a component and refresh the component.
CrudDemo function:
function CrudDemo(props) {
const navigate=useNavigate();
const location = useLocation();
//it runs for firsttime ,due to having second parameter as empthy array
useEffect(()=>{
debugger;
axios.get('http://localhost:60359/api/person/getpersons').then((res)=>{
const ResponseData=res.data;
setPersonList(ResponseData);
})
},[])
const [PersonList, setPersonList] = useState();
const [ShouldRefresh, setShouldRefresh] = useState(false);
return (
<div className="app">
<h2>All students <span role="img" aria-labelledby="love">📫</span>
</h2>
<button type="button" className="btn btn-info"onClick={() => navigate('/SavePerson/')}>Add Person</button>
<table className="table" >
<TableHeader></TableHeader>
<tbody>
{PersonList&&PersonList.map((student,i) => {
return (
<TableRow key={student.id} obj={student}></TableRow>
);
})}
</tbody>
</table>
</div>
);
}
export default CrudDemo;
and navigation code:
navigate('/CrudDemo/');
and inside crudCompnent there is a TableRow component:
function TableRow(props) {
return (
<tr >
<th>{props.obj.id}</th>
<th>{props.obj.personName}</th>
<th>
{ //Check if message failed
(props.obj.city!=null&&props.obj.city.name.length >0)
? <div> {props.obj.city.name} </div>
: <div> </div>
}
</th>
<th>{props.obj.personPhoneNumber}</th>
<th>
<TableAction id={props.obj.id}></TableAction>
</th>
</tr>
);
}
export default TableRow
and inside it there is a tableAction which responsible for redirect after delete action:
function TableAction(props) {
const navigate=useNavigate();
const handleClick = (e) => {
axios.get('http://localhost:60359/api/person/DeletePerson/'+props.id).then((res)=>{
const ResponseData=res.data;
console.log('person deleted message :',ResponseData);
navigate('/CrudDemo/');
//navigate('/home');
})
};
return (
<div>
<button type="button" className="btn btn-info"onClick={() => navigate('/PersonDetail/'+props.id,{state:{id:props.id}})}>Details</button>
<button type="button" className="btn btn-danger"onClick={handleClick}>Delete</button>
</div>
);
}
export default TableAction
to sum up ,there is a crudComponent which present data Table and inside it there is a tableRow component which responsible for showing each row and inside it there is a tableaction component which responsible for delete each row and redirect to crudComponent .Beside problem is that after redirection crudComponent isn't refreshed.
I handle it this way.Added location.state as a dependency in useEffect and send a state to it.
function CrudDemo(props) {
const navigate=useNavigate();
const location = useLocation();
//it runs for firsttime ,due to having second parameter as empthy array
useEffect(()=>{
debugger;
axios.get('http://localhost:60359/api/person/getpersons')
.then((res)=>{
const responseData=res.data;
setPersonList(responseData);
});
},[location.state]);
and in another component:
const handleClick = (e) => {
axios.get('http://localhost:60359/api/person/DeletePerson/'+props.id)
.then((res)=>{
const ResponseData=res.data;
console.log('person deleted message :',ResponseData);
navigate('/CrudDemo/',{state:{refresh:true}});
//navigate('/home');
});
};

How can I Send data to another Component without using Parent and Child Relation in React

I need to send the data to "Search" Component from "SearchingData" Component. SearchingData is the child of searchData, Here I need to send the "datacame" variable data to Search Component,Can anyone Help me out this, Thanks in Advance.
I need to access that "datacame" variable data to next Search Component, So Now How i can send that Data Search Component,Can anyone Help me out this, Thanks in Advance...
import React, { ChangeEvent, useState } from "react";
type searchData = {
handleSearch: (e: ChangeEvent<HTMLInputElement>) => void;
seardhingDTata: any;
seardhDTata: string;
};
const SearchingData: React.FC<searchData> = ({
handleSearch,
seardhingDTata,
seardhDTata,
}) => {
const UpdateData = (e: ChangeEvent<HTMLInputElement>) => {
handleSearch(e);
};
const [datacame, setdatacame] = useState(seardhDTata);
const serachData = () => {
let defaultData = seardhingDTata;
const filterdserachData = seardhDTata
? defaultData.filter((use: any) =>
use.UserName.toLowerCase().startsWith(seardhDTata)
)
: defaultData;
//console.log(filterdserachData);
setdatacame(filterdserachData);
};
return (
<React.Fragment>
<div>
<input type="text" onChange={UpdateData} />
<button className="btn btn-blue btn-sm" onClick={serachData}>
Serach
</button>
</div>
</React.Fragment>
);
};
export default SearchingData;
import React, { ChangeEvent } from "react";
import { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import SearchingData from "./SearchingData";
const Search: React.FC = () => {
let dispatch = useDispatch();
//Read the Data from Store
let readingStateData: searchReducsers.ISearch = useSelector(
(state: { searchingData: searchReducsers.ISearch }) => {
return state.searchingData;
}
);
// Update the Data
useEffect(() => {
//console.log(readingStateData.search)
dispatch(searchActions.fetchUser());
}, []);
const [seardhDTata, setseardhDTata] = useState("");
// const [searchText, setsearchText] = useState('');
const handlesearching = (e: ChangeEvent<HTMLInputElement>) => {
//console.log(e.target.value);
setseardhDTata(e.target.value);
};
const defaultData = readingStateData.search;
return (
<React.Fragment>
<div className="container mt-3">
<div className="row">
<div className="col-md-3">
<div className="card"></div>
</div>
</div>
</div>
<SearchingData
handleSearch={handlesearching}
seardhingDTata={defaultData}
seardhDTata={seardhDTata}
/>
<table className="table table-hover text-center table-primary">
<thead className="text-black">
<tr>
<th>UserName</th>
<th>Phone</th>
<th>Email</th>
<th>Gender</th>
</tr>
</thead>
<tbody>
<React.Fragment>
{defaultData.map((user) => {
return (
<tr>
<td>{user.UserName}</td>
<td>{user.PhoneNumber}</td>
<td>{user.email}</td>
<td>{user.gender}</td>
</tr>
);
})}
</React.Fragment>
</tbody>
</table>
</React.Fragment>
);
};
export default Search;
Have a state in the Search component which updates the state when we click on the button on the SearchingData. Now use this state to filter the data.
Searching Data Component
import React, { ChangeEvent, useState } from "react";
type searchData = {
setSearchText: (searchText: string) => void;
};
const SearchingData: React.FC<searchData> = ({
handleSearch,
}) => {
const [ searchInput, setSearchInput ] = useState('')
const serachData = () => {
setSearchText(searchInput);
};
return (
<React.Fragment>
<div>
<input type="text" value={searchInput} onChange={(e) => setSearchInput(e.target.value) } />
<button className="btn btn-blue btn-sm" onClick={serachData}>
Serach
</button>
</div>
</React.Fragment>
);
};
export default SearchingData;
Search Component
import React, { ChangeEvent } from "react";
import { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import SearchingData from "./SearchingData";
const Search: React.FC = () => {
let dispatch = useDispatch();
const [searchQuery, setSearchQuery] = useState("");
//Read the Data from Store
let readingStateData: searchReducsers.ISearch = useSelector(
(state: { searchingData: searchReducsers.ISearch }) => {
return state.searchingData;
}
);
// Update the Data
useEffect(() => {
//console.log(readingStateData.search)
dispatch(searchActions.fetchUser());
}, []);
const handlesearching = (searchText: string) => {
//console.log(e.target.value);
setSearchQuery(searchText);
};
const dataToDisplay = searchQuery.trim().length > 0 ? readingStateData.search.filter((use: any) =>
use.UserName.toLowerCase().startsWith(seardhDTata)
) : readingStateData.search;
return (
<React.Fragment>
<div className="container mt-3">
<div className="row">
<div className="col-md-3">
<div className="card"></div>
</div>
</div>
</div>
<SearchingData
setSearchText={handlesearching}
/>
<table className="table table-hover text-center table-primary">
<thead className="text-black">
<tr>
<th>UserName</th>
<th>Phone</th>
<th>Email</th>
<th>Gender</th>
</tr>
</thead>
<tbody>
<React.Fragment>
{dataToDisplay.map((user) => {
return (
<tr>
<td>{user.UserName}</td>
<td>{user.PhoneNumber}</td>
<td>{user.email}</td>
<td>{user.gender}</td>
</tr>
);
})}
</React.Fragment>
</tbody>
</table>
</React.Fragment>
);
};
export default Search;

How to Iterate the FilteredData and how to update in the UI using Redux with Typesecript

I got the State Data from Store. I created the Search Box to filter that Data, Now I got the FilterData also, But how I need to update my UI with that Filtered Data, In HandleSearch method I stored the the Filtered data in FilteredData varibale, But I am Unable to Iterate the FilteredData varibale and I am unable to update in the UI, BUt it is working in console, Now i need to update in the UI, Please can anyone help in this, Thanks in Advance...
import { Dispatch } from "redux"
import axios from 'axios'
export const FETCH_SUCCESS : string ='FETCH_SUCCESS';
export const FETCH_SEARCH ='FETCH_SEARCH';
export const fetchUser=()=>{
return async (dispatch:Dispatch) =>{
try{
let dataUrl : string ="http://localhost:3000/users";
let response = await axios.get(dataUrl);
dispatch({type:FETCH_SUCCESS, payload : response.data})
} catch {
}
}
}
import * as searchAction from './SearchAction';
import {SearchingInter} from '../../componets/SearchingInter';
export interface ISearch{
search : SearchingInter[]
}
let initialSate : ISearch ={
search : [] as SearchingInter[]
}
export const reducer =(state =initialSate , action:any) :ISearch =>{
switch(action.type){
case searchAction.FETCH_SUCCESS :
return {
...state,
search : action.payload
};
default : return state;
}
}
import React, { ChangeEvent } from 'react';
import {useEffect} from 'react';
import {useSelector,useDispatch} from 'react-redux';
import * as searchActions from '../Redux/SearchFetch/SearchAction';
import * as searchReducsers from '../Redux/SearchFetch/Searchreducer';
import SearchingData from './SearchingData';
const Search = () => {
let dispatch = useDispatch();
let readingStateData : searchReducsers.ISearch = useSelector((state : {searchingData:searchReducsers.ISearch})=>{
return state.searchingData;
})
useEffect(() => {
console.log(readingStateData.search)
dispatch(searchActions.fetchUser());
}, [])
const handlesearching =(e:ChangeEvent<HTMLInputElement>)=>{
//console.log(e.target.value);
let defaultData = readingStateData.search;
//console.log(defaultData);
const filteredData = e.target.value ? defaultData.filter(user =>user.UserName.toLowerCase().startsWith(e.target.value)) : defaultData
}
return (
<React.Fragment>
<div className="container mt-3">
<div className="row">
<div className="col-md-3">
<div className="card">
</div>
</div>
</div>
</div>
<SearchingData handleSearch={handlesearching}/>
<table className="table table-hover text-center table-primary">
<thead className="text-black">
<tr>
<th>UserName</th>
<th>Phone</th>
<th>Email</th>
<th>Gender</th>
</tr>
</thead>
<tbody>
<React.Fragment>
{
readingStateData.search.map(user =>{
return(
<tr>
<td>{user.UserName}</td>
<td>{user.PhoneNumber}</td>
<td>{user.email}</td>
<td>{user.gender}</td>
</tr>
)
})
}
</React.Fragment>
</tbody>
</table>
</React.Fragment>
)
}
export default Search;
import { type } from 'os';
import React, { ChangeEvent } from 'react'
type searchData = {
handleSearch : (e:ChangeEvent<HTMLInputElement>) => void;
}
const SearchingData:React.FC<searchData> = ({handleSearch}) => {
const UpdateData =(e:ChangeEvent<HTMLInputElement>)=>{
//console.log(e);
handleSearch(e)
}
return (
<React.Fragment>
<div>
<input type="text" onChange={UpdateData} />
</div>
</React.Fragment>
)
}
export default SearchingData
You need to have a state which will hold the filterData value. And set the initialValue of the state to the Data from the store
const [ dataToDisplay, setDataToDisplay ] = useState(readingStateData?.search || []);
Add a second useEffect which looks for the change in the readingStateData?.search. Initially you have the search as [] but once there is data we need to sync that data with the components's internal state.
useEffect(() => {
if(readingStateData?.search?.length > 0){
setDataToDisplay(readingStateData?.search)
}
}, [readingStateData?.search])
Now inside your handleChange you can update the state
const handlesearching =(e:ChangeEvent<HTMLInputElement>)=>{
const newDataToDisplay = e.target.value ? dataToDisplay.filter(user =>user.UserName.toLowerCase().startsWith(e.target.value)) : readingStateData?.search
setDataToDisplay(newDataToDisplay);
}
Now while rendering map over this dataToDisplay instead readingStateData?.search
dataToDisplay.map((user) => {
return (
<tr>
<td>{user.UserName}</td>
<td>{user.PhoneNumber}</td>
<td>{user.email}</td>
<td>{user.gender}</td>
</tr>
);
});
you can make your input as controlled input and have its value being read from the state
const Search = () => {
let dispatch = useDispatch();
let readingStateData: searchReducsers.ISearch = useSelector(
(state: {searchingData: searchReducsers.ISearch}) => {
return state.searchingData;
}
);
const [searchText, setSearchText] = useState('');
useEffect(() => {
console.log(readingStateData.search);
dispatch(searchActions.fetchUser());
}, []);
const handlesearching = (e: ChangeEvent<HTMLInputElement>) => {
setSearchText(e.target.value);
};
const dataToDisplay = searchText.trim().length > 0
? readingStateData?.search.filter((user) =>
user.UserName.toLowerCase().startsWith(searchText)
)
: readingStateData?.search;
return (
<React.Fragment>
<SearchingData handleSearch={handlesearching} searchText={searchText} />
{dataToDisplay.map((user) => {
return (
....
);
})}
</React.Fragment>
);
};
// In your Search Component add another prop called searchText
type searchData = {
handleSearch : (e:ChangeEvent<HTMLInputElement>) => void;
searchText: string;
}
const SearchingData:React.FC<searchData> = ({handleSearch, searchText}) => {
const UpdateData =(e:ChangeEvent<HTMLInputElement>)=>{
//console.log(e);
handleSearch(e)
}
return (
<React.Fragment>
<div>
<input type="text" value={searchText} onChange={UpdateData} />
</div>
</React.Fragment>
)
}
export default SearchingData

Is correct this update state in react?

Input event
public handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ emptyFields: false, error: false, loading: false });
this.setState({ product: { ...this.state.product, [e.target.name]: e.target.value } });
}
Map test
<tbody>
{this.props.products.map((prod: IProduct) =>{
console.log('remap ???')
return (<tr key={prod.id}>
<td>{prod.id}</td>
<td>{prod.name}</td>
<td>{prod.price}</td>
</tr>)
}
)}
</tbody>
When I change the input, this map is made again as many times as I change the input.
When you change the state, react will call the render method again.This is expected.
Break out parts of your html in seperate components and make the components pure. This will prevent needless re render of DOM. However; at the moment it won't re render dom because virtual DOM compare of React will optimize. You will get in trouble if each row gets props that are recreated every time the parent renders, like not using useCallback for the delete callback:
//use React.memo to create a pure component
const ProductRow = React.memo(function ProductRow({
product: { id, name },
onDelete,
}) {
console.log('generating jsx for product:', id);
return (
<tr>
<td>{id}</td>
<td>{name}</td>
<td>
<button onClick={() => onDelete(id)}>X</button>
</td>
</tr>
);
});
//React.memo is pure component, only re renders if
// props (=products or onDelete) change
const Products = React.memo(function Products({
products,
onDelete,
}) {
return (
<table>
<tbody>
<tr>
<th>id</th>
<th>name</th>
</tr>
{products.map((product) => (
<ProductRow
key={product.id}
product={product}
onDelete={onDelete}
/>
))}
</tbody>
</table>
);
});
const id = ((id) => () => ++id)(0); //create id
const AddProduct = React.memo(function AddProduct({
onAdd,
}) {
const [name, setName] = React.useState('');
//no use to use useCallback, this function re creates
// when name changes
const save = () => {
onAdd(name);
setName('');
};
return (
<div>
<label>
name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<button onClick={save}>save</button>
</div>
);
});
const App = () => {
//initial products state
const [products, setProducts] = React.useState(() => [
{ id: id(), name: 'first product' },
{ id: id(), name: 'second product' },
]);
//use useCallback to create an add function on mount
// this function is not re created causing no needless
// re renders for AddProduct
const onAdd = React.useCallback(
(name) =>
setProducts((products) =>
products.concat({
id: id(),
name,
})
),
[]
);
//delete function only created on mount
const onDelete = React.useCallback(
(id) =>
setProducts((products) =>
products.filter((product) => product.id !== id)
),
[]
);
return (
<div>
<AddProduct onAdd={onAdd} />
<Products products={products} onDelete={onDelete} />
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Is there something wrong with my react parent class?

I am practicing using react to build a simple table. Here my table has three columns. (name, job, delete). There is already some data in the table. In the third column, I want to build a button so the user can click and cancel the whole row
I already fixed several bugs but the table still does not show up
const TableBody = props => {
const rows = props.fillTheData.map((row, index) => {
return (
<tr key={index}>
<td>{row.name}</td>
<td>{row.job}</td>
<td><button onClick={() => props.removeCharacter(index)}>Delete</button></td>
</tr>
);
});
return <tbody>{rows}</tbody>;
}
class App extends React.Component {
state = {
character : [ ]
};
removeCharacter = index => {
const {character} = this.state;
this.setState({
character: character.filter((element, i) => {
return i !== index;
})
});
}
handleSubmit = character => {
this.setState({character:[...this.state.character,character]})
}
render() {
return(
<div class= "container">
<Table characters = {this.state.character} removeCharacter = {this.removeCharacter} />
<Form handleSubmit = {this.handleSubmit}/>
</div>
)
}
}
class Form extends React.Component {
constructor (props) {
super( props );
this.initialState = {
name: '',
job: ''
};
this.state = this.initialState;
}
handleChange = event => {
const{name,job} = event.target;
this.setState(
{
[name]: value
}
);
}
submitForm = () => {
this.props.handleSubmit(this.state);
this.setState(this.initialState);
}
render() {
const { name, job } = this.state;
return (
<div class="container2">
<form>
<label>Name</label>
<input
type="text"
name="name"
value={name}
onChange={this.handleChange} />
<label>Job</label>
<input
type="text"
name="job"
value={job}
onChange={this.handleChange}/>
</form>
<input
type="button"
value="Submit"
onClick={this.submitForm} />
</div>
);
}
}
export default Form;
class Table extends React.Component {
render(){
const {characters, removeCharacter} = this.props;
return(
<table>
<TableHeader />
<TableBody fillTheData = {characters} removeCharacter= {removeCharacter} />
</table>
)
}
}
const TableHeader = () => {
return (
<thead>
<tr>
<th>Name</th>
<th>Job</th>
<th>Delete</th>
</tr>
</thead>
);
}
Right now, we have a cool Table component, but the data is being hard-coded. One of the big deals about React is how it handles data, and it does so with properties, referred to as props, and with state. First, we’ll focus on handling data with props.
Then let’s move all that data to an array of objects, as if we were bringing in a JSON-based API. We’ll have to create this array inside our render().
The handleChange method of Form component is declaring a constant named job which doesn't exist in event.target object and it is setting the state with value variable which doesn't exists in that scope.
So change
const{name,job} = event.target;
to
const{name,value} = event.target;
your code will just work fine.

Resources