I'm creating a React Native Android App that pulls data from a database and displays it.
I would like to run a Javascript Function before the render() displays the variables.
as
render() {
return (
<View><Text>{ data }</Text></View>
);
}
Doesn't work because the variables aren't defined yet.
You can make use of componentDidMount function to call an api (if you want to call it only once) that returns you the data which you can save in the state and render
class App extends React.Component {
state = {
data: [],
loading: true
}
componentDidMount() {
ApiCall().then((data) => {
this.setState({data, loading: false})
})
}
render() {
if(this.state.loading) {
return 'Loading...'
}
return (
<View><Text>{this.state.data.map((obj => <View>{/* return that you want here from obj*/}</View>))}</Text></View>
);
}
}
To enhance UserExperience, you can have a loading state till your data is ready.
Related
In my componentDidMount() I am making an API call "invokeservice" to fetch some data, this call then sets a state object that I use in my render.
The problem I am having is that the invokeservice is not being called and set the first time that the page is loaded, however when I refresh the page the invokeservice returns the data fine and the rest of the script will run. It's only the first time that it returns an null value.
Is it possible to call this invoke service in render function and keep the data ready and display it when user tries to load this page.
TRIED:
1.read that ComponentDidMount is called only after 1st initial render.
2. {this.invokeservice()} i tried to call in render function before return which did initial render but after 5sec it was blank and then again 5sec later it is filled again with values.
render function
public render() {
return (
<div className="monitor">
<div className="monitor__table">
{this.monitorrow(translate("cpu"), this.state.cpuString)}
{this.monitorrow(translate("memory"), this.state.pmemoryString)}
</div>
</div>
);
}
constructor
constructor(props) {
super(props);
this.state = {
cpu: 0,
cpuString: ""
};
setInterval(() => this.invokeservice(), 5000);
}
componentdidMount
public componentDidMount() {
this.invokeservice();
}
invokeservice
private invokeservice() {
var client = new HttpClient();
var url = this.props.baseUrl + '//getMonitorUsage' + '?NC=' + Date.now().toString();
client.get(url, (response) => {
this.setState({
cpu: JSONResponse.GetSystemStateResult.CPUusage
});
}
}
});
}
function
monitorrow(left,right) {
return (
<div className="table__row">
<div className="table__cell__left">
<Text>{left}</Text>
</div>
{ right &&
(<div className="table__cell__right">
<Text>{right}</Text>
</div>)
}
</div>
);
}
It is expected.
From the react docs:
These methods are called in the following order when an instance of a component is being created and inserted into the DOM:
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
Ref: https://reactjs.org/docs/react-component.html
There is componentWillMount which will be called before render(). But is it not advised to be used. Read more on the official docs https://reactjs.org/docs/react-component.html#unsafe_componentwillmount
In my react app I have a main App component where I fetched data from api in componentDidMount method and saved it in its state. Then I passed that state to another component in App. However, when I consume that data from prop it is showing undefined.
Another strange this I didn't is when I console.log state in App components render method them first I get an empty array then after a second another array with the data in it. Please help me here
The code goes like this-
class App extends React.Component {
constructor() {
super();
this.state = {
data: []
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
fetch(
`https://api.themoviedb.org/3/movie/popular?api_key=${
process.env.REACT_APP_API_KEY
}&language=en-US&page=1`
)
.then(res => res.json())
.then(data => {
this.setState({ data });
})
.catch(err => console.log(err));
}
render() {
console.log(this.state.data);
return (
<div>
<Movie title="Popular" results={this.state.data} />
</div>
);
}
}
export default App;
this.state.data is undefined in Movie component which is like this
function Movie(props) {
return (
<p>{props.data.results[0].title}</p>
)
}
You are passing results and title as the props to the <Movie> component yet trying to fetch data prop.
component:
<Movie title="Popular" results={this.state.data} />
So you need to fetch the results prop, not the data one.
fixed:
function Movie(props) {
return (
<p>{props.results[0].title}</p>
)
}
additionaly:
If you're already passing the title prop, why not just use that prop for the title?
function Movie(props) {
return (
<p>{props.title}</p>
)
}
Your prop is results so you need to reference that in your component:
function Movie(props) {
return (
<p>{props.results[0].title}</p>
)
}
In your App component you might also want to add a check in render to show a loading message or spinner if the data load hasn't been resolved when the component initially renders:
if (!this.state.data.length) return <Spinner />;
In my componentDidMount(), I am calling an actionCreator in my redux file to do an API call to get a list of items. This list of items is then added into the redux store which I can access from my component via mapStateToProps.
const mapStateToProps = state => {
return {
list: state.list
};
};
So in my render(), I have:
render() {
const { list } = this.props;
}
Now, when the page loads, I need to run a function that needs to map over this list.
Let's say I have this method:
someFunction(list) {
// A function that makes use of list
}
But where do I call it? I must call it when the list is already available to me as my function will give me an error the list is undefined (if it's not yet available).
I also cannot invoke it in render (before the return statement) as it gives me an error that render() must be pure.
Is there another lifecycle method that I can use?
Just do this, and in redux store please make sure that initial state of list should be []
const mapStateToProps = state => {
return {
list: someFunction(state.list)
};
};
These are two ways you can play with received props from Redux
Do it in render
render() {
const { list } = this.props;
const items = list && list.map((item, index) => {
return <li key={item.id}>{item.value}</li>
});
return(
<div>
{items}
</div>
);
}
Or Do it in componentWillReceiveProps method if you are not using react 16.3 or greater
this.state = {
items: []
}
componentWillReceiveProps(nextProps){
if(nextProps.list != this.props.list){
const items = nextProps.list && nextProps.list.map((item, index) => {
return <li key={item.id}>{item.value}</li>
});
this.setState({items: items});
}
}
render() {
const {items} = this.state;
return(
<div>
{items}
</div>
);
}
You can also do it in componentDidMount if your Api call is placed in componentWillMount or receiving props from parent.
I am developing React + Redux single page application. I have a table with documents in page and I need to refresh data every 20 seconds. There are two functions in javascript: setTimeout and setInterval. I guess I can't use setInterval, because it just call function after some period of time. In my case I need to call function and wait for response (request processing in backend takes some time). So I used setTimeout and wrote this component (now it's simplified):
import {connect} from 'react-redux';
const { DATA_REFRESH_TIMEOUT, RETRY_REFRESH_TIMEOUT } = __ENVIRONMENT_CONFIG__;
#connect(
(state) => ({
documents: state.documents.documents,
loadingDocuments: state.documents.loading
}),
(dispatch) => bindActionCreators(
{
dispatchLoadDocuments: loadDocuments
},
dispatch
)
)
export default class Dashboard extends Component {
documentasTimeoutId;
constructor(props) {
super(props);
this.state = {
documentType: null
};
}
....
handleDocumentTypeChange = (event, documentType) => {
//If document type was changed I must to abort current timer
//and get documents with particular type immediately
this.setState({documentType: documentType});
this.clearTimeoutAndGetDocuments(documentType);
};
getDocuments = (documentType) => {
//Here I am checking for document loading phase
//If it is loading, we will wait and repeat loading after short time
const{ loadingDocuments } = this.props;
if(!loadingDocuments) {
this.props.dispatchLoadDocuments(documentType);
} else {
this.documentasTimeoutId = setTimeout(() => { this.getDocuments(documentType); }, RETRY_REFRESH_TIMEOUT);
}
};
clearTimeoutAndGetDocuments = (documentType) => {
//Abort delayed data getting and get data immediately
clearTimeout(this.documentasTimeoutId);
this.getDocuments(documentType);
};
componentDidMount(){
//Load documents on start up
this.props.dispatchLoadDocuments();
}
componentWillReceiveProps(newProps) {
//Here I trying to get event when documents loaded
let areDocumentsJustLoaded = this.props.loadingDocuments && !newProps.loadingDocuments;
if(areDocumentsJustLoaded) {
//If they loaded, I am setting timeout to refresh documents after some time
this.documentasTimeoutId = setTimeout(() => { this.getOutstandingFailures(this.state.search); }, DATA_REFRESH_TIMEOUT);
}
}
render() {
const {columns, documents} = this.props;
return (
//.....
<DataTable
columns={columns}
source={documents}
title="Documents"
name="documents"
emptyMessage="No data"/>
//....
);
}
}
As you can see I'm getting documents and loadingDocuments from reducer. I put documents to my DataTable, and by loadingDocuments changes I can define when data loading completed.
It's working, but I'am not sure for correct react and redux using (I am a newbie in React/Redux). Maybe there a better approach to do same actions? Maybe we can somehow create a separate component for this purpose and reuse it in other pages?
I am using Redux thunk and axios to make server calls and modify the state depending on the result.
The problem is that when I use a connected component, and its initial state depends on data from the server, it does not render (the connected props are empty)
render () (<div>{this.props.someData}</data>) // empty, or error, if nested
...
const mapStateToProps = state => ({
someData: state.someData
})
I also tried this:
componentWillMount = () => {
this.setState({
someData: this.props.someData
})
}
And used state in render, but it didn't help.
Is there a way to wait for the server response before rendering or some other solution?
You can conditionally render that part. Use a property to indicate fetching status (property name is loading in my example).
class UserDetails extends React.Component {
state = {
loading: true,
data: null
}
fetch() {
this.setState({
loading: true
})
// an axios call in your case
setTimeout(() => this.setState({
loading: false,
data: {
nestedValue: 'nested value'
}
}), 500)
}
componentDidMount() {
this.fetch()
}
render() {
return <div>
{this.state.loading ? <span>loading...</span> : <div>nested prop value: {this.state.data.nestedValue}</div>}
</div>
}
}
Typically you would use the Component.defaultProps object to initialize your props. So in your case, something like this will set your someData prop to an initial value before axios receives the data.
class MyComponent extends React.Component {
// ... your implementation
}
MyComponent.defaultProps = {
someData: [] // empty array or whatever the data type is
};
Edit: docs