static getDerivedStateFromProps does't behave like componentwillreceiveprops? - reactjs

Hi I'm trying to implement search in child component , the parent component will get data from server and pass that data to child component
as props, now child component has to implement search on that data, I have used componentwillreceiveprops which is depreciated how can I implement
this without using componentwillreceiveprops, below is my code
working example on fiddle
class Parent extends React.Component{
constructor(props) {
super(props);
this.state = {
data: []
}
}
componentDidMount() {
// mimic api call
const data = [
{ key: 'react'}, { key: 'redux'},
{ key: 'javascript' }, { key: 'Ruby'} ,{key: 'angular'}
]
setTimeout(this.setState({data}), 3000);
}
render() {
return (
<React.Fragment>
<ChildComponent data = {this.state.data}/>
</React.Fragment>
)
}
}
class ChildComponent extends React.Component{
constructor(props) {
super(props);
this.state = {
data: []
}
}
componentwillreceiveprops(nextProps){
this.setState({data: nextProps.data})
}
search(e){
console.log('props,', e.target.value)
let searchedData = this.props.data.filter(el => {
return el.key.startsWith(e.target.value)
})
this.setState({data: searchedData})
};
render(){
return(
<div>
search for (react, redux, angular, ruby)
<br/> <br/> <br/>
<input type = 'text' onChange={this.search.bind(this)}/>
{this.state.data.map(d => {
return (<div key={d.key}>{d.key}</div>)
})}
</div>
)
}
}

getDerivedStateFromProps is not a direct replacement for componentWillReceiveProps. Its just meant to update state in response to any update and unlike componentWillReceiveProps, getDerivedStateFromProps is triggered on every update either from child or from parent so you cannot simply update state without any conditional check. In order to update state if the props changed, you need to store the previous props in the state of child too or update the key of child so that it triggers a re-render
There are two possible approaches to this. Below is an example of first approach with getDerivedStateFromProps
import React from "react";
import ReactDOM from "react-dom";
import _ from "lodash";
import "./styles.css";
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
componentDidMount() {
// mimic api call
const data = [
{ key: "react" },
{ key: "redux" },
{ key: "javascript" },
{ key: "Ruby" },
{ key: "angular" }
];
setTimeout(() => {
this.setState({ data });
setTimeout(() => {
this.setState(prev => ({ data: [...prev.data, { key: "Golang" }] }));
}, 3000);
}, 3000);
}
render() {
return (
<React.Fragment>
<ChildComponent data={this.state.data} />
</React.Fragment>
);
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
static getDerivedStateFromProps(props, state) {
if (!_.isEqual(props.data, state.prevData)) {
return {
data: props.data,
prevData: state.data
};
} else {
return {
prevData: props.data
};
}
}
search(e) {
console.log("props,", e.target.value);
let searchedData = this.props.data.filter(el => {
return el.key.startsWith(e.target.value);
});
this.setState({ data: searchedData });
}
render() {
return (
<div>
search for (react, redux, angular, ruby)
<br /> <br /> <br />
<input type="text" onChange={this.search.bind(this)} />
{this.state.data.map(d => {
return <div key={d.key}>{d.key}</div>;
})}
</div>
);
}
}
function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Parent />, rootElement);
Working DEMO
Second approach involves changing the key of the child component instead of implementing getDerivedStateFromProps
import React from "react";
import ReactDOM from "react-dom";
import _ from "lodash";
import "./styles.css";
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
keyData: 0
};
}
componentDidMount() {
// mimic api call
const data = [
{ key: "react" },
{ key: "redux" },
{ key: "javascript" },
{ key: "Ruby" },
{ key: "angular" }
];
setTimeout(() => {
this.setState(prev => ({ data, keyData: (prev.keyData + 1) % 10 }));
setTimeout(() => {
this.setState(prev => ({
data: [...prev.data, { key: "Golang" }],
keyData: (prev.keyData + 1) % 10
}));
}, 3000);
}, 3000);
}
render() {
return (
<React.Fragment>
<ChildComponent data={this.state.data} key={this.state.keyData} />
</React.Fragment>
);
}
}
class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
data: props.data
};
}
search(e) {
console.log("props,", e.target.value);
let searchedData = this.props.data.filter(el => {
return el.key.startsWith(e.target.value);
});
this.setState({ data: searchedData });
}
render() {
return (
<div>
search for (react, redux, angular, ruby)
<br /> <br /> <br />
<input type="text" onChange={this.search.bind(this)} />
{this.state.data.map(d => {
return <div key={d.key}>{d.key}</div>;
})}
</div>
);
}
}
function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Parent />, rootElement);
Working DEMO
You can go ahead with the second method when you know that you will have quite a few updates in the child component whereas update from parent will be less frequent and the props that you have to compare getDerivedStateFromProps is nested . In such as case implementing getDerivedStateFromProps will be less performant than updating the key since you will need to perform expensive computation on each render.

To implement your componentWillReceiveProps() behavior using the new getDerivedStateFromProps() method, you can replace your current componentwillreceiveprops() hook with this:
static getDerivedStateFromProps(nextProps, state){
/* Return the new state object that should result from nextProps */
return { data : nextProps.data }
}
The getDerivedStateFromProps() will be called before your component is rendered and, if a non-null value is returned, then that return value will become the state of the component.
In your case, the state of the <ChildComponent> component has only one data field which is populated directly from props, so returning { data : nextProps.data } would be sufficent to update the data state field to match the incoming data prop.
The general idea is that you can use this method to update a component's state based on changing/incoming props.
See this documentation for more information on getDerivedStateFromProps() - hope that helps!
Update
Also on another note, it seems the way <Parent> is updating state via the setTimeout method is incorrect. You should update it as follows:
// Incorrect: setTimeout(this.setState({data}), 3000);
setTimeout(() => this.setState({data}), 3000);

Related

My checkbox is not changing from check or uncheck, but I can see that state value is changing, what's going on?

So when I run this and check the checkbox, I can see the values changing in the state, but why is the checkbox control not changing its status from check/uncheck? I know the render() method is being hit as well. Why, oh why, Gods of code? Lost in hours of figuring out what's wrong and I'm lost!
bob-Todos.js FILE
class Todo extends React.Component {
constructor(param) {
super();
this.state = {
id: param.data.id,
text: param.data.text,
completed: param.data.completed,
onMyChange: param.OnChange,
};
}
render() {
console.log("In TODO Render");
return (
<div>
<p>
<input
type="checkbox"
onChange={() => {
this.state.onMyChange(this.state.id);
}}
checked={this.state.completed}
/>
{this.state.text}
</p>
</div>
);
}
}
export default Todo;
Bob-App.js FILE
import React, { Component } from "react";
import Todo from "./bob-Todo";
import todoData from "../data/bob-todosData";
class App extends Component {
constructor() {
super();
this.state = { data: todoData };
this.OnChange = this.OnChange.bind(this);
}
OnChange(myId) {
this.setState((prev) => {
let updatedTodos = prev.data.map((todo) => {
if (todo.id === myId) {
todo.completed = !todo.completed;
}
return todo;
});
return { data: updatedTodos };
});
console.log(this.state.data);
}
render() {
return this.state.data.map((item) => {
return <Todo key={item.id} data={item} OnChange={this.OnChange} />;
});
}
}
export default App;
bob-todosData.js FILE
const todosData = [
{
id: 1,
text: "take out the trash",
completed: true
},
{
id: 2,
text: "rest for a while and relax",
completed: false
},
{
id: 3,
text: "watch an online movie",
completed: true
}
]
export default todosData
index.js FILE
import React from 'react';
import ReactDOM from 'react-dom';
import AppBob from "./bobComponents/Bob-App";
ReactDOM.render(
<AppBob />, document.getElementById('root')
);
You don't need to assign your props to state in your Todo component
Just remove them and invoke the function also use those variables directly:
Then your component will be:
class Todo extends React.Component {
render() {
const {
data: {
id,
text,
completed,
},
OnChange, // <-- Should rename this to "onChange"
} = this.props;
console.log('In TODO Render');
return (
<div>
<p>
<input
type="checkbox"
onChange={() => {
OnChange(id);
}}
checked={completed}
/>
{text}
</p>
</div>
);
}
}
export default Todo;
Also, rename your OnChange function to onChange to enable js convention

Child component not triggering rendering when parent injects props with differnt values

Here are my components:
App component:
import logo from './logo.svg';
import {Component} from 'react';
import './App.css';
import {MonsterCardList} from './components/monster-list/monster-card-list.component'
import {Search} from './components/search/search.component'
class App extends Component
{
constructor()
{
super();
this.state = {searchText:""}
}
render()
{
console.log("repainting App component");
return (
<div className="App">
<main>
<h1 className="app-title">Monster List</h1>
<Search callback={this._searchChanged}></Search>
<MonsterCardList filter={this.state.searchText}></MonsterCardList>
</main>
</div>
);
}
_searchChanged(newText)
{
console.log("Setting state. new text: "+newText);
this.setState({searchText:newText}, () => console.log(this.state));
}
}
export default App;
Card List component:
export class MonsterCardList extends Component
{
constructor(props)
{
super(props);
this.state = {data:[]};
}
componentDidMount()
{
console.log("Component mounted");
this._loadData();
}
_loadData(monsterCardCount)
{
fetch("https://jsonplaceholder.typicode.com/users", {
method: 'GET',
}).then( response =>{
if(response.ok)
{
console.log(response.status);
response.json().then(data => {
let convertedData = data.map( ( el, index) => {
return {url:`https://robohash.org/${index}.png?size=100x100`, name:el.name, email:el.email}
});
console.log(convertedData);
this.setState({data:convertedData});
});
}
else
console.log("Error: "+response.status+" -> "+response.statusText);
/*let data = response.json().value;
*/
}).catch(e => {
console.log("Error: "+e);
});
}
render()
{
console.log("filter:" + this.props.filter);
return (
<div className="monster-card-list">
{this.state.data.map((element,index) => {
if(!this.props.filter || element.email.includes(this.props.filter))
return <MonsterCard cardData={element} key={index}></MonsterCard>;
})}
</div>
);
}
}
Card component:
import {Component} from "react"
import './monster-card.component.css'
export class MonsterCard extends Component
{
constructor(props)
{
super(props);
}
render()
{
return (
<div className="monster-card">
<img className="monster-card-img" src={this.props.cardData.url}></img>
<h3 className="monster-card-name">{this.props.cardData.name}</h3>
<h3 className="monster-card-email">{this.props.cardData.email}</h3>
</div>
);
}
}
Search component:
import {Component} from "react"
export class Search extends Component
{
_searchChangedCallback = null;
constructor(props)
{
super();
this._searchChangedCallback = props.callback;
}
render()
{
return (
<input type="search" onChange={e=>this._searchChangedCallback(e.target.value)} placeholder="Search monsters"></input>
);
}
}
The problem is that I see how the text typed in the input flows to the App component correctly and the callback is called but, when the state is changed in the _searchChanged, the MonsterCardList seems not to re-render.
I saw you are using state filter in MonsterCardList component: filter:this.props.searchText.But you only pass a prop filter (filter={this.state.searchText}) in this component. So props searchTextis undefined.
I saw you don't need to use state filter. Replace this.state.filter by this.props.filter
_loadData will get called only once when the component is mounted for the first time in below code,
componentDidMount()
{
console.log("Component mounted");
this._loadData();
}
when you set state inside the constructor means it also sets this.state.filter for once. And state does not change when searchText props change and due to that no rerendering.
constructor(props)
{
super(props);
this.state = {data:[], filter:this.props.searchText};
}
If you need to rerender when props changes, use componentDidUpdate lifecycle hook
componentDidUpdate(prevProps)
{
if (this.props.searchText !== prevProps.searchText)
{
this._loadData();
}
}
Well, in the end I found what was happening. It wasn't a react related problem but a javascript one and it was related to this not been bound to App class inside the _searchChanged function.
I we bind it like this in the constructor:
this._searchChanged = this._searchChanged.bind(this);
or we just use and arrow function:
_searchChanged = (newText) =>
{
console.log("Setting state. new text: "+newText);
this.setState({filter:newText}, () => console.log(this.state));
}
Everything works as expected.

How to pass the changed state from child component to its parent in ReactJS

I am trying to understand how to pass a changed state from child component to its parent in ReactJS? so far the following code changes the child state but not the parents state, any clue what I am doing wrong?
I am using redux to get product array from mongodb.
Product array example:
[
{
“_id”: “2331”,
“department”: “Shoes”,
“category”: “Shoes/Women/Pumps”,
“name”: “Calvin Klein”,
“title”: “Evening Platform Pumps”,
“description”: “Perfect for a casual night out or a formal event.”,
“style”: “Designer”,
"colors": ["red","yellow","red","black"]
},
{
“_id”: “30671”,
“department”: “Shoes”,
“category”: “Shoes/Women/Pumps”,
“name”: “zara”,
“title”: “Evening Platform Pumps”,
“description”: “Perfect for a casual night out or a formal event.”,
“style”: “Designer”,
"colors": ["red","yellow","red","black"]
}
]
Parent Component
import React, { Component } from 'react'
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
products: [],
};
}
componentDidMount() {
this.props.getProducts();
}
componentDidUpdate(prevProps, prevState) {
if (this.props.product.products !== prevState.products) {
this.setState({ products: this.props.product.products });
}
}
onUpdateProducts = (e) => {
const newProducts = this.state.products;
this.props.updateProductName(newProducts);
};
render() {
const { products } = this.state;
if (isEmpty(products)) {
productContent = (
<div>
<p className="lead text-muted">Error Empty Products </p>
</div>
);
} else {
const productArr = products.map((product) => (
<Child key={product._id} product={product} />
));
productContent = (
<div>
{productArr}
</div>
);
}
return (
<div className="container">
{productContent}
<div className="row">
<div className="col-md-12">
<button className="btn " onClick={this.onUpdateProducts}>
Submit
</button>
</div>
</div>
</div>
)
}
}
const mapStateToProps = (state) => ({
product: state.product
});
export default connect(mapStateToProps, {
getProducts,updateProductName
})(Parent);
Child Component
import React, { Component } from 'react'
export default class Child extends Component {
constructor(props) {
super(props);
this.state = {
product: this.props.product,
};
}
componentDidUpdate(prevProps, prevState) {
if (this.props.product !== prevProps.product) {
this.setState({
product: this.props.product
});
}
}
onChangeProductName = (e) => {
const newProduct = Object.assign({}, this.state.product, {
name: e.target.value
});
this.setState({ product: newProduct }, function() {
console.log('onChangeProductName: ', this.state.product);
});
};
render() {
const { product } = this.state;
return (
<div>
<TextInput
placeholder="Product Name"
name="prd_name"
value={product.name}
onChange={this.onChangeProductName}
/>
</div>
)
}
}
There are two ways for a child component to update the parent component:
Without using Redux, you can pass a function as a prop of the child component, so the child component can call this function to update the parent component.
Store the data in the Redux store. The child component dispatches an action which updates the Redux state, where the parent component gets data.
A simple example would explain the concept of passing the changed state from child to the parent.
Component A:
export default class A extends Component{
//This is a callback
handleStateChange = (value) ={
console.log("value", value);//you get the value here when state changes in B(Child) component
}
render(){
return(
<div>
<B handleStateChange={this.handleStateChange} />
</div>
)
}
}
Component B:
export Class B extends Component{
constructor(props){
super(props);
this.state={
value: "01"
}
}
handleButton = () => {
const value = "02";
this.setState({
value: "02"
});
this.props.handleStateChange(value);
}
render(){
return(
<div>
<button onClick={this.handleButton} />
</div>
)
}
}
Or you can directly pass the state if you call this.props.handleStateChange(this.state.value); this in render directly on any event handler if you want to pass updated state
As #Ying zuo mentioned you need to use redux to get the changed state value of child component in parent component.
When state changes in child component, you make a redux action call by passing the value as param and set that in the state in reducer and get the state in your parent component
Hope that explains the concept.
You have to pass the child a function.
In the child component you are setting state to be equal to props value, and then you are updating state. This has no connection to parent class - you also shouldn't modify props just as an aside.
The solution is to pass a function from the parent to child. This function will update the parent state, and because you are passing the parent state to the child, it will also be updated.
So in your parent class you could do something like:
onChangeProductName = (value, i) => {
const new_product_array = [...this.state.products];
new_product_array[i].name = value;
this.setState({ products: new_product_array});
};
You would need to pass this to the child
const productArr = products.map((product, i) => (
<Child
key={product._id}
product={product} onChangeName={this.onChangeProductName.bind(this)}
index={i} />
));
And then call it in the child
<TextInput
placeholder="Product Name"
name="prd_name"
value={product.name}
onChange={() => this.props.onChangeName(product, this.props.index)}
/>
The child component then doesn't need all the state tracking.

function passed as React prop is not appearing in called child

I have a React component render method defined as below, which includes passing a prop called onExchangeSelect into the ExchangeList component.
render() {
return (
<div className="ExchangeContainer list-group">
<ExchangeList
exchanges={this.state.exchanges} selected={this.state.selectedExchange}
onExchangeSelect={selectedExchange => this.setState({selectedExchange})}
/>
<ExchangeDetail exchange={this.state.selectedExchange} />
</div>
);
}
Then, in the ExchangeList constructor, when I console.log this.props, there is not a prop called onExchangeSelect which I can call and th.
The intent is to pass a callback function from the top level component to a child component, to be called by the child so as to affect the state of the parent component. The entire top-level class is below:
class ExchangeContainer extends Component {
constructor(props) {
super(props);
this.state = {
exchanges:[
{
name:"binance",
url:"https://bittrex.com"
},
{
name:"bittrex",
url:"https://bittrex.com"
}
],
selectedExchange:"binance"
};
}
render() {
return (
<div className="ExchangeContainer list-group">
<ExchangeList
exchanges={this.state.exchanges} selected={this.state.selectedExchange}
onExchangeSelect={selectedExchange => this.setState({selectedExchange})}
/>
<ExchangeDetail exchange={this.state.selectedExchange} />
</div>
);
}
}
Why is the function not available as a prop in the child component? (below):
class ExchangeList extends Component {
constructor(props) {
super(props);
this.state = {
};
console.log('This props ' + JSON.stringify(this.props))
}
render() {
console.log("EL: " + JSON.stringify(this.props))
const ExItemList = this.props.exchanges.map((exchange) => {
return <ExchangeListItem key={exchange.name} exchange={exchange}
onExchangeSelect={this.props.onExchangeSelect}/>
});
return (
<ul className="col-md-4 list-group bg-light" >
{ExItemList}
</ul>
);
}
}
i would inspect them in dev tools instead of console.log..place break point and check in chrome dev tool.. onExchangeSelect should be available as part of props in child component..
the offical docs says you should bind the method to a property inside the constructor function. you can play around on my codesandbox for the code below
constructor(props) {
super(props);
this.state = {
exchanges: [
{
name: "binance",
url: "https://bittrex.com"
},
{
name: "bittrex",
url: "https://bittrex.com"
}
],
selectedExchange: "binance"
};
// bind "this" to handleOnExchange method
this.handleOnExchange = this.handleOnExchange.bind(this);
}
// method to be bound
handleOnExchange (data) {
this.setState({selectedExchange: data})
}
render() {
const ExchangeList = props => <div />;
const ExchangeDetail = props => <div />;
return (
<div className="ExchangeContainer list-group">
<ExchangeList
exchanges={this.state.exchanges}
selected={this.state.selectedExchange}
// pass the method to a child property (onExchangeSelect)
onExchangeSelect={this.handleOnExchange}
/>
<ExchangeDetail selectedExchange={this.state.selectedExchange} />
</div>
);
}
to use it inside a (class-based) child component, call the method with an arg like this:
this.props.onExchangeSelect(arg)
The reason it can't see it is because you are looking for it in the wrong place. You are looping through the "exchange" props to create a new component so when you reference "this.props.onExchangeSelect", you are not referring the the props passed to the class as you expected but to the exchange object through which you are looping.
To remedy this, consider rewriting the ExchangeContainer component like so:
class ExchangeContainer extends Component {
constructor(props) {
super(props);
this.state = {
exchanges:[
{
name:"binance",
url:"https://bittrex.com"
},
{
name:"bittrex",
url:"https://bittrex.com"
}
],
selectedExchange:"binance"
};
}
setSelectedExchange = (selectedExchange) =>{
this.setState({selectedExchange})
};
render() {
return (
<div className="ExchangeContainer list-group">
<ExchangeList
exchanges={this.state.exchanges} selected={this.state.selectedExchange}
onExchangeSelect={selectedExchange => setSelectedExchange(selectedExchange)}
/>
<ExchangeDetail exchange={this.state.selectedExchange} />
</div>
);
}
}
And the ExchangeList component like so:
class ExchangeList extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
console.log("EL: " + JSON.stringify(this.props));
const {exchanges, selected, onExchangeSelect} = this.props;
const ExItemList = exchanges.map((exchange) => {
return <ExchangeListItem key={exchange.name} exchange={exchange}
onExchangeSelect={onExchangeSelect}/>
});
return (
<ul className="col-md-4 list-group bg-light" >
{ExItemList}
</ul>
);
}
}

save react component and load later

I have react component in react native app and this will return Smth like this:
constructor(){
...
this.Comp1 = <Component1 ..... >
this.Comp2 = <Component2 ..... >
}
render(){
let Show = null
if(X) Show = this.Comp1
else Show = this.Comp1
return(
{X}
)
}
and both of my Components have an API request inside it ,
so my problem is when condition is changed and this toggle between Components , each time the Components sent a request to to that API to get same result ,
I wanna know how to save constructed Component which they wont send request each time
One of the ways do that is to handle the hide and show inside each of the child component comp1 and comp2
So you will still render both comp1 and comp2 from the parent component but you will pass a prop to each one of them to tell them if they need to show or hide inner content, if show then render the correct component content, else just render empty <Text></Text>
This means both child components exist in parent, and they never get removed, but you control which one should show its own content by the parent component.
So your data is fetched only once.
Check Working example in react js: https://codesandbox.io/s/84p302ryp9
If you checked the console log you will find that fetching is done once for comp1 and comp2.
Also check the same example in react native below:
class Parent extends Component {
constructor(props)
{
super(props);
this.state={
show1 : true //by default comp1 will show
}
}
toggleChild= ()=>{
this.setState({
show1 : !this.state.show1
});
}
render(){
return (
<View >
<Button onPress={this.toggleChild} title="Toggle Child" />
<Comp1 show={this.state.show1} />
<Comp2 show={!this.state.show1} />
</View>
)
}
}
Comp1:
class Comp1 extends Component
{
constructor(props) {
super(props);
this.state={
myData : ""
}
}
componentWillMount(){
console.log("fetching data comp1 once");
this.setState({
myData : "comp 1"
})
}
render(){
return (
this.props.show ? <Text>Actual implementation of Comp1</Text> : <Text></Text>
)
}
}
Comp2:
class Comp2 extends Component {
constructor(props) {
super(props);
this.state = {
myData2: ""
}
}
componentWillMount() {
console.log("fetching data in comp2 once");
this.setState({
myData2: "comp 2"
});
}
render() {
return (
this.props.show ? <Text>Actual implementation of Comp2</Text> : <Text></Text>
)
}
}
I think, you should move all your logic to the main component (fetching and saving data, so you component1 and component2 are simple dumb components. In component1 and component2 you can check "does component have some data?", if there isn't any data, you can trigger request for that data in parent component.
Full working example here: https://codesandbox.io/s/7m8qvwr760
class Articles extends React.Component {
componentDidMount() {
const { fetchData, data } = this.props;
if (data && data.length) return;
fetchData && fetchData();
}
render() {
const { data } = this.props;
return (
<div>
{data && data.map((item, key) => <div key={key}>{item.title}</div>)}
</div>
)
}
}
class App extends React.Component{
constructor(props){
super(props);
this.state = {
news: [],
articles: [],
isNews: false
}
}
fetchArticles = () => {
const self = this;
setTimeout( () => {
console.log('articles requested');
self.setState({
articles: [{title: 'article 1'}, {title: 'articles 2'}]
})
}, 1000)
}
fetchNews = () => {
const self = this;
setTimeout(() => {
console.log('news requested');
self.setState({
news: [{ title: 'news 1' }, { title: 'news 2' }]
})
}, 1000)
}
handleToggle = (e) => {
e.preventDefault();
this.setState({
isNews: !this.state.isNews
})
}
render(){
const { news, articles, isNews} = this.state;
return (
<div>
<a href="#" onClick={this.handleToggle}>Toggle</a>
{isNews? (
<News data={news} fetchData={this.fetchNews} />
): (
<Articles data={articles} fetchData={this.fetchArticles} />
)}
</div>
)
}
}

Resources