Reputation: 155
Using React and React-Dom CDN 16
I am new to React and trying to build a dashboard component that takes the value of one of three buttons in a Buttons component and sends the value to a List component. The List component fetches data from an API and renders the results.
The feature works fine up until the data fetching, which it only does once the app is rendered the first time. I've logged that the state that's set by the Buttons component is making its way to the List component and the fetch action is updating dynamically correctly, but the fetching functionality isn't getting triggered when that state updates.
Here's the code.
const { useState, useEffect } = React
const App = props => {
return (
<div className="app-content">
<Dashboard />
</div>
);
};
const Dashboard = props => {
const [timespan, setTimespan] = useState('week');
const changeTime = time => setTimespan(time);
return(
<div>
<p>{timespan}</p> // this state updates when the buttons are clicked
<Buttons onUpdate={changeTime} />
<List timespan={timespan}/>
</div>
);
};
const Buttons = props => {
return (
<div>
<button onClick={props.onUpdate.bind( this, 'week' )}>
week
</button>
<button onClick={props.onUpdate.bind( this, 'month' )}>
month
</button>
<button onClick={props.onUpdate.bind( this, 'all' )}>
all
</button>
</div>
);
};
const List = props => {
const timespan = props.timespan;
const homepage = `${location.protocol}//${window.location.hostname}`;
const action = `${homepage}?fetchDataset=1×pan=${timespan}`;
// if I console.log(action) here the URL is updated correctly
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [obj, setObj] = useState([]);
useEffect(() => {
fetch(action)
.then(res => res.json())
.then(
(result) => { // if I console.log(result) here I only get a response at initialization
setIsLoaded(true);
setObj(result);
},
(error) => {
setIsLoaded(true);
setError(error);
}
)
}, []);
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div>
// my API returns "timespan is: $timespan", but this is only ever "week" because that's the initial state of the timespan
{obj}
</div>
);
};
};
ReactDOM.render(
<App />,
document.getElementById('app')
);
I think I must be overlooking something very obvious because this seems like one of the core purposes of React, but it's hard to find documentation that is relevant with version 16 updates like function classes and hooks.
I really appreciate any help. Thanks!
Upvotes: 2
Views: 66
Reputation: 2086
you need to add timeSpan
(or action
) to your useEffect
dependency array:
useEffect(() => {
fetch(action)
.then(res => res.json())
.then(
result => {
setIsLoaded(true);
setObj(result);
},
error => {
setIsLoaded(true);
setError(error);
}
);
}, [timeSpan]); // [action] will also solve this
This way the effect will know it needs to run every time the timeSpan
prop changes.
By passing an empty dependency array you are telling the effect to only run once - when the component it mounted.
Upvotes: 1