I have introduced some serious breaking bugs into my react app somehow, and I do not understand how to fix it. Yesterday the data from runSearch was showing up to the main component SearchPage, but today the search will not even run at all. The SearchPage defaults the data to empty strings, meaning at worst the page would display tables without any data, but for some reason the data passed to the children becomes undefined, not empty strings. As an error pops up due to undefined values, the search for info does not even run at all
SearchPage.js
import React, {useState, useEffect} from 'react';
import { connect } from 'react-redux';
import axios from 'axios';
import SearchBar from './SearchBar';
// import AllDividendsDisplay from './dividend_results_display/AllDividendsDisplay';
import DividendResultsDisplay from './dividend_results_display/DividendResultsDisplay';
import AllEarningsDisplay from './earnings_results_display/AllEarningsDisplay';
import SettingsView from './settings/SettingsView';
import debounceTerm from '../hooks';
const HOST = process.env.REACT_APP_HOSTNAME
const PROTOCOL = process.env.REACT_APP_PROTOCOL
const PORT = process.env.REACT_APP_PORT
const BASE_URL = PROTOCOL + '://' + HOST + ':' + PORT
const SearchPage = ({userId}) => {
const DEFAULT_STOCK = 'ibm';
const [term, setTerm] = useState();
const [debouncedTerm, setDebouncedTerm] = useState();
const [loading, setLoading] = useState(false);
const [recentSearches, setRecentSearches] = useState([DEFAULT_STOCK]);
const [dividendsYearsBack, setDividendsYearsBack] = useState('3');
const [debouncedDividendYearsBack, setDebouncedDividendYearsBack] = useState('3');
const [errorMessage, setErrorMessage] = useState('');
const [dividendsData, setDividendsData] = useState(
{
current_price: '',
recent_dividend_rate: '',
current_yield: '',
dividend_change_1_year: '',
dividend_change_3_year: '',
dividend_change_5_year: '',
dividend_change_10_year: '',
all_dividends: [],
name: '',
description: '',
}
)
const [settingsViewVisible, setSettingsViewVisible] = useState(false);
// const [showYieldChange, setShowYieldChange] = useState(true);
// const [showAllDividends, setShowAllDividends] = useState(true);
const [displaySettings, setDisplaySettings] = useState([
{setting_name: 'showYieldChange', visible: true},
{setting_name: 'showAllDividends', visible: true},
])
const onTermUpdate = (term) => {
const trimmed = term.trim()
setTerm(trimmed);
}
debounceTerm(setDebouncedTerm, term, 1500);
debounceTerm(setDebouncedDividendYearsBack, dividendsYearsBack, 1500);
useEffect(() => {runSearch()}, [debouncedTerm]);
useEffect(() => {
// alert(dividendsYearsBack)
if (dividendsYearsBack !== '') {
runSearch();
}
}, [debouncedDividendYearsBack])
useEffect(() => {
console.log("user id changed")
if (userId) {
const user_profile_api_url = BASE_URL + '/users/' + userId
axios.get(user_profile_api_url, {})
.then(response => {
console.log(response)
const recent_searches_response = response.data.searches;
const new_recent_searches = [];
recent_searches_response.map(dict => {
new_recent_searches.push(dict.search_term)
})
setRecentSearches(new_recent_searches);
setDisplaySettings(response.data.display_settings);
})
.catch((error) => {
console.log("error in getting user profile: ", error.message)
})
}
}, [userId])
useEffect(() => {
const user_profile_api_url = BASE_URL + '/users/' + userId
const request_data = {
searches: recentSearches,
display_settings: displaySettings
}
axios.post(user_profile_api_url, request_data)
// .then(response => {
// console.log(response)
// })
}, [recentSearches, displaySettings])
const makeSearchApiRequest = () => {
let dividends_api_url = BASE_URL + '/dividends/' + term + '/' + dividendsYearsBack
console.log(dividends_api_url);
if (!recentSearches.includes(term)) {
setRecentSearches([...recentSearches, term])
}
axios.get(dividends_api_url, {})
.then(response => {
// console.log(response.data)
setLoading(false);
setDividendsData(response.data);
})
.catch((error) => {
console.log(error.message);
setLoading(false);
setErrorMessage(error.message);
})
}
const runSearch = () => {
console.log("running search: ", term);
setErrorMessage('');
if (term) {
setLoading(true);
if (!dividendsYearsBack) {
setDividendsYearsBack('3', () => {
makeSearchApiRequest()
});
} else {
makeSearchApiRequest()
}
}
}
const recentSearchOnClick = (term) => {
setTerm(term);
setDebouncedTerm(term);
}
const removeRecentSearchOnClick = (term) => {
const searchesWithoutThisOne = recentSearches.filter(search => search !== term)
setRecentSearches(searchesWithoutThisOne);
}
const dividendsYearsBackOnChange = (text) => {
const trimmed = text.trim()
setDividendsYearsBack(trimmed);
}
const generateShowToggler = (setter, state) => {
return function() {
setter(!state);
}
}
const generateToggleDisplaySetting = (setting_name) => {
return function() {
const otherSettings = displaySettings.filter((dict) => dict.setting_name !== setting_name);
const specifiedSetting = displaySettings.find((dict) => dict.setting_name == setting_name);
specifiedSetting.visible = !specifiedSetting.visible
const newDisplaySettings = [...otherSettings, specifiedSetting]
setDisplaySettings(newDisplaySettings)
}
}
const renderMainContent = () => {
if (!debouncedTerm) {
return (
<div className="ui active">
<div className="ui text">Search for info about a stock</div>
</div>
)
}
if (loading === true) {
return (
<div className="ui active dimmer">
<div className="ui big text loader">Loading</div>
</div>
)
}
if (errorMessage) {
return (
<div className="ui active">
<div className="ui text">{errorMessage}</div>
</div>
)
} else {
return (
<div>
<DividendResultsDisplay
dividendsData={dividendsData}
dividends_years_back={dividendsYearsBack}
dividendsYearsBackOnChange={dividendsYearsBackOnChange}
displaySettings={displaySettings}
toggleYieldChange={generateToggleDisplaySetting('showYieldChange')}
toggleAllDividends={generateToggleDisplaySetting('showAllDividends')}/>
<br/>
<AllEarningsDisplay earnings={dividendsData.earnings} />
</div>
)
}
}
// https://stackoverflow.com/questions/38619981/how-can-i-prevent-event-bubbling-in-nested-react-components-on-click
const renderRecentSearches = () => {
return recentSearches.map((term) => {
return (
<div key={term}>
<button
onClick={() => recentSearchOnClick(term)}
style={{marginRight: '10px'}}
>
<div>{term} </div>
</button>
<button
onClick={(event) => {event.stopPropagation(); removeRecentSearchOnClick(term)}}>
X
</button>
<br/><br/>
</div>
)
})
}
// console.log("displaySettings: ", displaySettings);
console.log("dividendsData")
console.log(dividendsData)
return (
<div className="ui container" style={{marginTop: '10px'}}>
<SearchBar term={term} onTermUpdate={onTermUpdate} />
{renderRecentSearches()}
<div className="ui segment">
{renderMainContent()}
</div>
</div>
)
}
const mapStateToProps = state => {
return { userId: state.auth.userId };
};
export default connect(
mapStateToProps
)(SearchPage);
// export default SearchPage;
the display main component:
import React, {useState} from 'react';
import MainDividendResultsDisplay from './MainDividendResultsDisplay';
import DividendYieldChangeDisplay from './DividendYieldChangeDisplay';
import AllDividendsDisplay from './AllDividendsDisplay';
const DividendResultsDisplay = (props) => {
const [descriptionVisible, setDescriptionVisible] = useState(false);
const toggleDescription = (event) => {
setDescriptionVisible(!descriptionVisible);
}
const renderDescription = () => {
if (descriptionVisible) {
return (
<p style={{cursor: 'pointer'}} onClick={toggleDescription}>{props.dividendsData.summary}</p>
)
} else {
return (
<a style={{cursor: 'pointer'}} onClick={toggleDescription}>Description <div className="ui icon caret up"></div></a>
)
}
}
console.log("data object in DividendResultsDisplay")
console.log(props.dividendsData)
console.log("current price DividendResultsDisplay")
console.log(props.dividendsData.current_price)
const mainInfo = (
<MainDividendResultsDisplay
current_price={props.dividendsData.current_price}
recent_dividend_rate={props.dividendsData.recent_dividend_rate}
current_yield={props.dividendsData.current_yield}
/>
)
const yieldChange = (
<DividendYieldChangeDisplay
displaySettings={props.displaySettings}
toggleYieldChange={props.toggleYieldChange}
dividend_change_1_year={props.dividendsData.dividend_change_1_year}
dividend_change_3_year={props.dividendsData.dividend_change_3_year}
dividend_change_5_year={props.dividendsData.dividend_change_5_year}
dividend_change_10_year={props.dividendsData.dividend_change_10_year}
/>
)
const allDividends = (
<AllDividendsDisplay
displaySettings={props.displaySettings}
toggleAllDividends={props.toggleAllDividends}
all_dividends={props.dividendsData.all_dividends}
dividends_years_back={props.dividends_years_back}
dividendsYearsBackOnChange={props.dividendsYearsBackOnChange}/>
)
console.log("data in DividendResultsDisplay")
console.log(props.data)
// console.log("props.data.all_dividends in DividendResultsDisplay")
// console.log(props.data.all_dividends)
return (
<div>
<h3>{props.data.name}</h3>
<h4>{props.data.sector}</h4>
{renderDescription()}
<br/><br/>
{mainInfo}
<br/>
{yieldChange}
<br/>
{allDividends}
</div>
)
};
export default DividendResultsDisplay;
one of the display subcomponents also getting undefined value to its prop:
import React from 'react';
import './DividendResults.css';
const AllDividendsDisplay = (props) => {
console.log("props in AllDividendsDisplay")
console.log(props)
let dividends_rows = null;
if (props.all_dividends) {
dividends_rows = props.all_dividends.map((dividends_object) => {
return (
<tr key={dividends_object.date}>
<td>{dividends_object.date}</td>
<td>{dividends_object.amount}</td>
</tr>
)
});
}
const allDividendsDisplaySetting = props.displaySettings.find((dict) => dict.setting_name == 'showAllDividends');
let mainDisplay = null;
if (allDividendsDisplaySetting.visible) {
mainDisplay = (
<table className="ui celled table">
<thead>
<tr>
<th>Date</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{dividends_rows}
</tbody>
</table>
)
}
return (
<div>
<h3>The dividends for the last
<input
type="text"
style={{width: '48px'}}
value={props.dividends_years_back}
onChange={(e) => props.dividendsYearsBackOnChange(e.target.value)}
/> years:
<div
style={{cursor: 'pointer'}}
onClick={props.toggleAllDividends}>
{allDividendsDisplaySetting.visible ? '-' : '+'}
</div>
</h3>
{mainDisplay}
</div>
);
};
export default AllDividendsDisplay;
Data is successfully being loaded in the search now but it still shows up as undefined
all the data
the API endpoint on local works fine
.env file:
REACT_APP_HOSTNAME=localhost
REACT_APP_PROTOCOL=http
REACT_APP_PORT=8000
The issue can be seen here: