Refresh react component - javascript

My node.js server sends with socket.io new data each 10s. In my web application I update this.state each time that my server sends data and force to update with forceUpdate()
However, my react component doesn't refresh, I don't know why. I followed the doc but I missed something...
Parent :
class DataAnalytics extends React.Component {
constructor(props) {
super(props);
socket = this.props.socket;
this.state = {data: []};
socket.on('dataCharts', (res) => {
console.log("new data charts : "+res);
var data = JSON.parse(res);
this.setState({data: data});
this.forceUpdate();
});
}
componentWillUnmount() {
socket.off('dataCharts');
}
render() {
return (
<div id="dataAnalytics">
<Stats data={this.state.data}></Stats>
</div>
);
}
}
export default DataAnalytics;
Child :
class Stats extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="stats" style={{textAlign:'center'}}>
<h4>Number: </h4>
</div>
);
}
componentDidUpdate() {
var data = this.props.data;
if(!jQuery.isEmptyObject(data)) {
$( ".stats" ).html("<h4>Number : data['nb']['counterIn']</h4>");
}
}
}
export default Stats;
Anyone know how to refresh automatically my React component.

The React component doesn't update because it doesn't realize that it's state changes. You can force an update on a React component by creating it each time with a different key attribute.
render() {
return (
<div id="dataAnalytics">
<Stats key={this.uniqueId()} data={this.state.data}></Stats>
</div>
);
}
// Example of a function that generates a unique ID each time
uniqueId: function () {
return new Date().getTime();
}

I usually do it like -
function MyComponent() {
const [_, refresh] = useState()
useEffect(() => {
// Code that's supposed to run on refresh
}, [refresh])
return
<>
{/* Rest of the code */}
<button onclick={() => refresh(true)}>Refresh</button>
</>
}
The idea is to define a state and use it as a dependency of useEffects (or useMemos and useCallbacks).
If there are multiple effect hooks, add refresh to all of them as a dependency.

Related

Re-render child after parent state change with get request

So I'm a beginner with react and I was wondering how to re-render the child after setting the state in the parent (from the child). Here's a code sample. I have a function that calls a GET request using Axios and when I press the button in the child component ideally it will update the state in the parent and also re-render the child but it only does the former.
Parent:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
fetchData = () => {
axios
.get(url)
.then(res => this.setState({data: res.data}))
}
Render() {
return (<Child data={this.state.data} fetchData={this.fecthData}/>)
}
// ...
Child:
class Child extends Component {
// ...
render() {
const { data, fetchData } = this.props
// render data
return <button onClick={fetchData}>Change data then fetch</button>
}
}
Also, are you supposed to make a local state in the Child and set it as a copy of the Parent's state or just passing it down as a prop is okay?
Your parent component holds the data and the child uses it. It seems to me you're doing it the right way. Here is a fully working example:
Codesandbox
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
data: []
};
this.updateData = this.updateData.bind(this);
}
async fetchData() {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
return response.json();
}
updateData() {
this.setState({ data: [] }) // Creates a flicker, just so you see it does refresh the child
this.fetchData().then((res) => this.setState({ data: res }));
}
render() {
return <Child data={this.state.data} onAction={this.updateData} />;
}
}
Note I renamed your child prop fetchData into onAction (I don't know what's the name of the action that triggers a refresh, could be onRefresh). It's always best to see components props with separation between data attributes and event attributes.
Even standard components have it this way: <input value={user.firstname} onChange={doSomething} />. So, better to prefix events by on, then the parent decides what to do with it. It's not the child's concern.
class Child extends Component {
render() {
const { data, onAction } = this.props;
return (
<>
<button onClick={onAction}>Change data then fetch</button>
{data.map((item) => (
<div key={item.id}>
{item.id} - {item.title}
</div>
))}
</>
);
}
}

Component sending undefined via props, because it is mounted before a database query ends

I have a problem related to the asynchronous world with react native.
I need to perform a database query, this query returns me a city vector, this vector should be sent to a picker via props.
The problem is: I perform the query within the ComponentWillUpdate function (by default it's the first function to call before mounting the screen). But even using componentWillMount the component (picker) is being assembled and sending undefined via props.
The data that should be sent is not being processed on time.
The flow of my program is being:
Starts the query (componentWillMount) -> rendering components (render) -> End of Query.
Is it possible to pause the screen mount until the query in ComponentWillUpdate ends?
I tried using async but dont work.
async componentWilldMount() {
try {
await axios.get(`${server}/getdata`)
.then(
//code
})
.catch(function (error) {
//handle error
})
} catch (err) {
// handle error
}
}
It's impossible to pause or stop the rendering the component. What you can do though is to set some property in your state like let's say data. So in your constructor you will have omething like that:
constructor(props) {
this.state = {
data: null
}
}
Then in your componentWillMount or even better componentDidMount you do:
componentDidMount() {
axios.get(`${server}/getdata`)
.then(response => {
this.setState({
data: response
})
)
.catch(function (error) {
//handle error
})
Last step is to render depending on your data so in your render method:
render() {
if(!state.data) {
return null;
}
<SomeComponent data={this.state.data} />
}
Solution : Use isReady flag in the parent component.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isReady: false,
}
}
componentDidMount() {
setTimeout(() => {
this.setState({value: "bbb", isReady: true});
}, 5000)
}
render() {
return (
<div>
{this.state.isReady && <Child value={this.state.value} />}
</div>
);
}
}
class Child extends React.Component {
constructor(props) {
super(props);
console.log(props.value);
}
render() {
return (
<div>{this.props.value}</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>

How can I call a function from one component to another? React

I'm working in react.js. I've created a component Backend.jsx. I want it to work as a service (like in angular) where I can send API requests. I want to call methods of Backend in some other components.
I called this backend service in component and try to send data and get it in BackendService using props.
But obviously this will not work.
Here's my code
In Component:
This will be called after form submit.
handleLoginSubmit = (event) => {
event.preventDefault();
console.log(this.state.data);
<BackendService onSendData = {this.state.data} />
}
In BackendService:
constructor(props) {
super(props);
this.state = { }
this.login(props)
}
login = (props) =>
{
console.log('login', props);
};
Any suggestions how can I call this login method in component. Or any other suggestion to get component data in service.
You can try this:
1.Component.js
class Componet extends React.Component {
constructor(props) {
super(props);
this.state={
data:"this state contain data"
}
this.backendServiceRef = React.createRef(); // Using this ref you can access method and state of backendService component.
}
render() {
return (
<div className="App">
<button onClick={() => {
this.backendServiceRef.current.login()
}}>click</button>
<BackendService ref={this.backendServiceRef} onSendData = {this.state.data}></BackendService>
</div>
);
}
}
export default Componet;
2.BackendService.js
class BackendService extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
login = (props) => {
alert("login call")
};
render() {
return (
<div>
Backend service component
</div>
)
}
}

Why is my react component not re rendering when props comes into the component?

I am currently in a project, and I have had to do null checks on every single props that has come in to children components wether through redux or passing it in myself. I feel like that is not normal with react? Isn't a huge plus side of React is automatic re-rendering? If I try to put anything into state, I can't because There has to be a null check in the render before I do anything with the data. Thanks in advance!!
PARENT COMPONENT =
class App extends Component {
componentDidMount(){
//where I load the data
this.loadCardsFromServer();
this.props.GetAllData();
}
render() {
//NEED TO DO A NULL CHECK FROM THIS COMING FROM REDUX
const filteredData = !!this.state.data ? this.state.data.filter(card =>{
return card.name.toUpperCase().includes(this.state.input.toUpperCase())
}) : null;
return (
//MAKES ME DO ANOTHER NULL CHECK
<div>
{!!this.state.data ? filteredData.map(i => <Card person={i} key={i.created} planet={this.props.planets} />) : null}
</div>
))}
CHILD COMPONENT OF CARD
class Card extends Component {
//WHERE I WANT TO PUT THE PROPS
constructor(){
super();
this.state={
edit: false,
name: this.props.person.name,
birthYear: this.props.person.birth_year
}
}
render() {
let world = null;
//ANOTHER NULL CHECK
if(this.props.planet){
this.props.planet.map(i => {
if(i.id === this.props.person.id){
world = i.name
}
})
}
return (
<div>
//THIS IS WHERE I WANT THE VALUE TO BE STATE
{this.state.edit ? <input label="Name" value={this.state.name}/> : <div className='card-name'>{name}</div>}
</div>
You need to update state when data arrive.
You can do it like this:
import React, { Component } from 'react';
import './App.scss';
import Card from './Components/Card/Card.js';
class App extends Component {
constructor(){
super();
this.state = {
loading:true,
cards:[]
};
}
componentDidMount(){
this.loadCardsFromServer();
}
loadCardsFromServer = () => {
let cardsResponseArray = [];
// fetch your cards here, and when you get data:
// cardsResponseArray = filterFunction(response); // make function to filter
cardsResponseArray = [{id:1,name:'aaa'},{id:2,name:'bbb'}];
setTimeout(function () {
this.setState({
loading:false,
cards: cardsResponseArray
});
}.bind(this), 2000)
};
render() {
if(this.state.loading === true){
return(
<h1>loading !!!!!!!!</h1>
);
} else {
return (
<div>
{this.state.cards.map(card => (
<Card key={card.id} card={card}></Card>
))}
</div>
);
}
}
}
export default App;
And then in your Card component:
import React, { Component } from 'react';
class Card extends Component {
constructor(props){
super(props);
this.props = props;
this.state = {
id:this.props.card.id,
name:this.props.card.name
};
}
render() {
return (
<div className={'class'} >
Card Id = {this.state.id}, Card name = {this.state.name}
</div>
);
}
}
export default Card;
For those interested about React state and lifecycle methods go here
Okay, in this case i craft a little helper's for waiting state in my redux store. I fetch data somewhere (app) and i render a connected component waiting for fetched data in store:
const Loader = (props) => {
if (!props.loaded) {
return null;
}
<Card data={props.data}/>
}
const CardLoader = connect (state => {
return {
loaded: state.data !== undefined
data: state.data
}
})(Loader)
<CardLoader />

React: Pass Firebase Data Down Via Props

I'm trying to pass some Firebase data down from one component via props to another component, but it doesn't seem to be letting me iterate over the Firebase data in the child component.
App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
games: []
};
}
componentDidMount() {
const gamesRef = firebase.database().ref('games').orderByKey();
gamesRef.once('value', snap => {
snap.forEach((childSnapshot) => {
this.state.games.push(childSnapshot.val());
})
})
}
render() {
return (
<div className="App">
<Games data={ this.state.games } />
</div>
);
}
}
Games.js
class Games extends Component {
componentDidMount() {
console.log(this.props.data); // this logs successfully
}
render() {
return (
<div className="container">
<div className="Games flex flex-end flex-wrap">
{ this.props.data.map(function (game, i) {
return (
<h1>{ game.title }</h1>
)
}) }
</div>
</div>
);
}
}
For some reason I'm having a problem when trying to map() over my props.data. It's definitely being passed down to my Games component, because it's printing the console.log(this.props.data) to the console with the data it gets back from Firebase.
Do I have to wait for my Firebase data to resolve before mapping over it, and if so how do I do this?
Any help is appreciated. Thanks in advance!
I think the problem lies with your componentDidMount in your App class. You're updating state with
this.state.games.push(childSnapshot.val());
You shouldn't do that. State should only be updated with this.setState (or at the very least you should use this.forceUpdate()), as otherwise it will not re-render. I would instead advise doing
componentDidMount() {
const gamesRef = firebase.database().ref('games').orderByKey();
let newGames;
gamesRef.once('value', snap => {
snap.forEach((childSnapshot) => {
newGames.push(childSnapshot.val());
})
})
this.setState({games: newGames});
}
This will cause a re-render of the App component, causing the new data to be passed as a prop to the Games component.

Categories