Action doesn't receive the correct prop - javascript

I'm using React/Redux in this code and I'm trying to pass the correct prop by action. My intention is to change converter name on click modal button. But when I debbug, console server shows me the same action with no alteration clicking on confirm button.
My action in file actions:
export const saveOrUpdateConverter = converter => {
return {
converter,
type: CONVERTER.SAVE_OR_UPDATE_CONVERTER
};
};
The function I'm using to do that:
export const saveOrUpdateConverter = (converter, type) => {
const url = `${BASE_URL}/SaveOrUpdateConverter`;
let converterWithoutId = {
...converter,
Id: 0
};
return makeRequest(
{
method: "post",
url,
data: type === "edit" ? converter : converterWithoutId
},
(data, dispatch) => {
// if we are adding a new converter, we need to remove it from newConverters
if (type === "add") {
dispatch(actions.removeFromNewConverters(converter));
}
dispatch(actions.saveOrUpdateConverter(data));
},
true
);
};
The file where I'm calling the function
const handleSaveUpdateConverter = async () => {
let type = "edit";
return await props.saveOrUpdateConverter(converter, type);
};
Component receiving function by prop:
<AddOrEditConverterModal
converter={converter}
show={showEditConverterModal}
onCloseModal={() => setShowEditConverterModal(false)}
saveOrUpdateConverter={(converter, propsType) =>
handleSaveUpdateConverter(converter, propsType)
}
type={"edit"}
/>
I finally call the props saveOrUpdateConverter in other file:
const updateConverter = async () => {
if (converter.IntervalToSavePayload < 5) {
props.requestError(
true,
props.intl.formatMessage({
id: "modal.base.converter.interval.save.pyload.error"
})
);
return;
}
await props.saveOrUpdateConverter(converter, props.type);
debugger
props.onCloseModal();
};
Connect function to use saveOrUpdateConverter :
import { connect } from "react-redux";
import { saveOrUpdateConverter } from "Features/Devices/Converters/actions";
import ConverterPage from "./ConverterPage";
const mapStateToProps = state => ({
activeConverters: state.converter.activeConverters,
activeInstruments: state.instrument.activeInstruments
});
export default connect(mapStateToProps, {saveOrUpdateConverter})(ConverterPage);

Related

Invalid hook call which I can't seem to fix

title pretty much says it, I've looked at some examples, but none of the fixes really worked for me. I understand it's the const, moving it within the class and out of the export, no luck. Can't seem to get it working. Anyone got any ideas? Thank you.
I get the error below at the line const [ws, setWs] = useState();
"Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app"
export default function PlayerHoc(ComposedComponent) {
const [ws, setWs] = useState();
const [roomIp, setRoomIp] = useState();
useEffect(() => {
const wsUrl =
process.env.NODE_ENV == "development"
? "ws://localhost:8888"
: "ws://" + roomIp;
setWs(new WebSocket(wsUrl));
}, [roomIp]);
useEffect(() => {
if (!ws) return;
ws.onopen = () => {
ws.send("PlaybackRequest");
};
}, [ws]);
class PlayerHoc extends Component {
shouldComponentUpdate(nextProps) {
return nextProps.playing || (this.props.playing && !nextProps.playing);
}
componentDidUpdate(prevProps) {
if (prevProps.currentSong.id !== this.props.currentSong.id) {
const id = this.props.currentSong.id;
const other = this.props.currentSong.linked_from
? this.props.currentSong.linked_from.id
: null;
this.props.containsCurrentSong(other ? `${id},${other}` : id);
}
}
render = () => (
<ComposedComponent
{...this.props}
playContext={(context, offset) => this.props.playSong(context, offset)}
playSong={() => this.props.playSong()}
{...setRoomIp(this.props.roomIp)}
/>
);
}
//testbug
const mapStateToProps = state => {
return {
currentSong: state.playerReducer.status
? state.playerReducer.status.track_window.current_track
: {},
contains: state.libraryReducer.containsCurrent ? true : false,
trackPosition: state.playerReducer.status
? state.playerReducer.status.position
: 0,
playing: state.playerReducer.status
? !state.playerReducer.status.paused
: false
};
};
function nextSong(skip) {
ws.send(JSON.stringify({ type: "skipSong", data: skip }))
}
function previousSong(prev) {
ws.send(JSON.stringify({ type: "previousSong", data: prev }))
}
function pauseSong(pause) {
ws.send(JSON.stringify({ type: "pauseSong", data: pause }))
}
function playSong(play) {
ws.send(JSON.stringify({ type: "playSong", data: play }))
}
function seekSong(seek) {
ws.send(JSON.stringify({ type: "seekSong", data: seek }))
}
const mapDispatchToProps = dispatch => {
return bindActionCreators(
{
nextSong,
previousSong,
pauseSong,
playSong,
seekSong,
},
dispatch
);
};
return connect(mapStateToProps,mapDispatchToProps)(PlayerHoc);
}
Well, this is a mess. But let's try to refactor this into a working Higher Order Component.
There are several issues here, but the main ones are:
Defining a class component inside of a functional component
Improper use of hooks.
So lets start by defining a normal Higher Order Component. Lets call it withPlayer.
withPlayer is going to return a Class component.
Inside this class component we can do things like create a websocket, and build all of your player controls.
Then we can pass those player controls as props to the Wrapped Component.
Finally, our default export will apply our redux connect HOC. We can use the compose function from redux, to compose both withPlayer and connect onto our Wrapped Component.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { compose } from 'redux';
function withPlayer(WrappedComponent) {
return class extends Component {
constructor(props) {
super(props);
const wsUrl =
process.env.NODE_ENV == 'development' ? 'ws://localhost:8888' : 'ws://' + props.roomIp;
this.ws = new WebSocket(wsUrl);
}
shouldComponentUpdate(nextProps) {
return nextProps.playing || (this.props.playing && !nextProps.playing);
}
componentDidUpdate(prevProps) {
if (prevProps.currentSong.id !== this.props.currentSong.id) {
const id = this.props.currentSong.id;
const other = this.props.currentSong.linked_from
? this.props.currentSong.linked_from.id
: null;
this.props.containsCurrentSong(other ? `${id},${other}` : id);
}
}
nextSong = (skip) => {
this.ws.send(JSON.stringify({ type: 'skipSong', data: skip }));
};
previousSong = (prev) => {
this.ws.send(JSON.stringify({ type: 'previousSong', data: prev }));
};
pauseSong = (pause) => {
this.ws.send(JSON.stringify({ type: 'pauseSong', data: pause }));
};
playSong = (play) => {
this.ws.send(JSON.stringify({ type: 'playSong', data: play }));
};
seekSong = (seek) => {
this.ws.send(JSON.stringify({ type: 'seekSong', data: seek }));
};
render() {
return (
<WrappedComponent
{...this.props}
playContext={(context, offset) => this.playSong(context, offset)}
nextSong={this.nextSong}
previousSong={this.previousSong}
pauseSong={this.pauseSong}
playSong={this.playSong}
seekSong={this.seekSong}
/>
);
}
};
}
const mapStateToProps = (state) => {
return {
currentSong: state.playerReducer.status
? state.playerReducer.status.track_window.current_track
: {},
contains: state.libraryReducer.containsCurrent ? true : false,
trackPosition: state.playerReducer.status ? state.playerReducer.status.position : 0,
playing: state.playerReducer.status ? !state.playerReducer.status.paused : false,
};
};
export default compose(withPlayer, connect(mapStateToProps));
This is how you would use it
import withPlayer from './withPlayer'
const MyComponent = props => {
return <>You're Player wrapped component</>
}
export default withPlayer(Mycomponent);

Apollo MockedProvider not returning expected data

I wrote a hook that calls apollo useQuery. It's pretty simple:
useDecider:
import { useState } from 'react';
import { useQuery, gql } from '#apollo/client';
export const GET_DECIDER = gql`
query GetDecider($name: [String]!) {
deciders(names: $name) {
decision
name
value
}
}
`;
export const useDecider = name => {
const [enabled, setEnabled] = useState(false);
useQuery(GET_DECIDER, {
variables: {
name
},
onCompleted: data => {
const decision = data?.deciders[0]?.decision;
setEnabled(decision);
},
onError: error => {
return error;
}
});
return {
enabled
};
};
I'm trying to test it now and the MockedProvider is not returning the expected data:
import React from 'react';
import { render, screen } from '#testing-library/react';
import '#testing-library/jest-dom';
import { MockedProvider } from '#apollo/client/testing';
import { useDecider, GET_DECIDER } from './useDecider';
const getMock = (value = false, decider = '') => [
{
request: {
query: GET_DECIDER,
variables: {
name: decider
}
},
result: () => {
console.log('APOLLO RESULT');
return {
data: {
deciders: [
{
decision: value,
name: decider,
value: 10
}
]
}
};
}
}
];
const FakeComponent = ({ decider }) => {
const { enabled } = useDecider(decider);
return <div>{enabled ? 'isEnabled' : 'isDisabled'}</div>;
};
const WrappedComponent = ({ decider, value }) => (
<MockedProvider mocks={getMock(value, decider)} addTypename={false}>
<FakeComponent decider={decider} />
</MockedProvider>
);
describe('useDecider', () => {
it('when decider returns true', () => {
// should return true
render(<WrappedComponent decider="fake_decider" value={true} />);
screen.debug();
const result = screen.getByText('isEnabled');
expect(result).toBeInTheDocument();
});
});
I simplified your hook implementation and put together a working example:
import { useQuery, gql } from "#apollo/client";
export const GET_DECIDER = gql`
query GetDecider($name: [String]!) {
deciders(names: $name) {
decision
name
value
}
}
`;
export const useDecider = (name) => {
const { data } = useQuery(GET_DECIDER, { variables: { name } });
return { enabled: data?.deciders[0]?.decision || false };
};
Note that in the test I also updated your getBy to an await findBy:
describe("useDecider", () => {
it("when decider returns true", async () => {
// should return true
render(<WrappedComponent decider="fake_decider" value={true} />);
screen.debug();
const result = await screen.findByText("isEnabled");
expect(result).toBeInTheDocument();
});
});
This is because you need to wait for your API call to complete before the data will be on the page, hence you would not expect the data to be there on the first render.
From https://www.apollographql.com/docs/react/development-testing/testing/#testing-the-success-state
To test how your component is rendered after its query completes, you
can await a zero-millisecond timeout before performing your checks.
This delays the checks until the next "tick" of the event loop, which
gives MockedProvider an opportunity to populate the mocked result
try adding before your expect call
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});

Save search term on refresh React

I am simply looking to save and restore a search term(form data) when a page is refreshed/reloaded. I have tried several solutions to no avail.
Flow: A user submits a search term and is taken to Spotify to retrieve an accessToken, if it is not already available. The initial page is refreshed once the accessToken is retrieved, but the search must be re-entered. This is not good UX.
I concluded that Web Storage was they way to go, of course it is not the only route. I am not sure if this is something that should be relegated to Lifecycle methods: componentDidMount() & componentDidUpdate(). Perhaps that is overkill? In any event, I attempted to employ both localStorage and sessionStorage. My implementation is obviously off as I am not getting the expected result. React dev tools displays the state of the SearchBar term, but it is not being saved. Also of note is the following: React dev tools shows that the onSubmit event handler is registering as bound () {} instead of the expected bound handleInitialSearchTerm() {}. The console also shows that there are no errors.
No third-party libraries please.
SearchBar.js
import React from 'react';
import "./SearchBar.css";
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
term: this.handleInitialSearchTerm
};
this.search = this.search.bind(this);
this.handleInitialSearchTerm = this.handleInitialSearchTerm.bind(this);
this.setSearchTerm = this.setSearchTerm.bind(this);
this.handleSearchOnEnter = this.handleSearchOnEnter.bind(this);
this.handleTermChange = this.handleTermChange.bind(this);
}
handleInitialSearchTerm = (event) => {
if (typeof (Storage) !== "undefined") {
if (localStorage.term) {
return localStorage.term
} else {
return this.setSearchTerm(String(window.localStorage.getItem("term") || ""));
}
}
};
setSearchTerm = (term) => {
localStorage.setItem("term", term);
this.setState({ term: term });
}
search() {
this.props.onSearch(this.state.term);
}
handleSearchOnEnter(event) {
if (event.keyCode === 13) {
event.preventDefault();
this.search();
}
}
handleTermChange(event) {
this.setState({
term: event.target.value
});
}
render() {
return (
<div className="SearchBar">
<input
placeholder="Enter A Song, Album, or Artist"
onChange={this.handleTermChange}
onKeyDown={this.handleSearchOnEnter}
onSubmit={this.handleInitialSearchTerm}
/>
<button className="SearchButton" onClick={this.search}>
SEARCH
</button>
</div>
);
}
}
export default SearchBar;
Motify.js
let accessToken;
const clientId = "SpotifyCredentialsHere";
const redirectUri = "http://localhost:3000/";
const CORS = "https://cors-anywhere.herokuapp.com/"; // Bypasses CORS restriction
const Motify = {
getAccessToken() {
if (accessToken) {
return accessToken;
}
// if accessToken does not exist check for a match
const windowURL = window.location.href;
const accessTokenMatch = windowURL.match(/access_token=([^&]*)/);
const expiresInMatch = windowURL.match(/expires_in=([^&]*)/);
if (accessTokenMatch && expiresInMatch) {
accessToken = accessTokenMatch[1]; //[0] returns the param and token
const expiresIn = Number(expiresInMatch[1]);
window.setTimeout(() => accessToken = "", expiresIn * 1000);
// This clears the parameters, allowing us to grab a new access token when it expires.
window.history.pushState("Access Token", null, "/");
return accessToken;
} else {
const accessUrl = `https://accounts.spotify.com/authorize?client_id=${clientId}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectUri}`;
window.location = accessUrl;
}
},
search(term) {
const accessToken = Motify.getAccessToken();
const url = `${CORS}https://api.spotify.com/v1/search?type=track&q=${term}`;
return fetch(url, { headers: { Authorization: `Bearer ${accessToken}` }
}).then(response => response.json()
).then(jsonResponse => {
if (!jsonResponse.tracks) {
return [];
}
return jsonResponse.tracks.items.map(track => ({
id: track.id,
name: track.name,
artist: track.artists[0].name,
album: track.album.name,
uri: track.uri,
preview_url: track.preview_url
}));
})
}
...
Please check the code I have added.
Changes I did are below:
1)
this.state = {
term: JSON.parse(localStorage.getItem('term')) || '';
};
setSearchTerm = (term) => {
this.setState({
term: term
},
() => {
localStorage.setItem('term', JSON.stringify(this.state.term)));
}
import React from 'react';
import "./SearchBar.css";
class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
term: JSON.parse(localStorage.getItem('term')) || '';
};
this.search = this.search.bind(this);
this.handleInitialSearchTerm = this.handleInitialSearchTerm.bind(this);
this.setSearchTerm = this.setSearchTerm.bind(this);
this.handleSearchOnEnter = this.handleSearchOnEnter.bind(this);
this.handleTermChange = this.handleTermChange.bind(this);
}
handleInitialSearchTerm = (event) => {
if (typeof(Storage) !== "undefined") {
if (localStorage.term) {
return localStorage.term
} else {
return this.setSearchTerm(String(window.localStorage.getItem("term") || ""));
}
}
};
setSearchTerm = (term) => {
this.setState({
term: term
},
() => {
localStorage.setItem('term', JSON.stringify(this.state.term)));
}
search() {
this.props.onSearch(this.state.term);
}
handleSearchOnEnter(event) {
if (event.keyCode === 13) {
event.preventDefault();
this.search();
}
}
handleTermChange(event) {
this.setState({
term: event.target.value
});
}
render() {
return ( <
div className = "SearchBar" >
<
input placeholder = "Enter A Song, Album, or Artist"
onChange = {
this.handleTermChange
}
onKeyDown = {
this.handleSearchOnEnter
}
onSubmit = {
this.handleInitialSearchTerm
}
/> <
button className = "SearchButton"
onClick = {
this.search
} >
SEARCH <
/button> <
/div>
);
}
}
export default SearchBar;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
If it is in hooks i would have done like below:
import React, {
useEffect,
useState,
useRef,
} from 'react';
function App() {
const [value, setValue] = useState(() => {
if (localStorage.getItem('prevCount') === null) {
return 0;
} else {
return localStorage.getItem('prevCount');
}
});
const countRef = useRef();
useEffect(() => {
countRef.current = value;
if (countRef.current) {
localStorage.setItem('prevCount', countRef.current);
} else {
localStorage.setItem('prevCount', 0);
}
});
const handleIncrement = () => {
setValue((value) => +value + 1);
};
const handleDecrement = () => {
if (value === 0) {
return;
} else {
setValue((value) => value - 1);
}
};
return (
<div className="card">
<label className="counterLabel">Simple Counter</label>
<button
className="button"
onClick={handleIncrement}
>
Increment
</button>
<span className="count">{value}</span>
<button
className="button"
onClick={handleDecrement}
>
Decrement
</button>
</div>
);
}
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
So what the above code is doing is that when we inititalize the state value we first check the localStorage , if "term" has value in localStorage we will use that value or else an empty string is initialized.
Using callback of setState inside the method setSearchTerm we set the term value immediately
Try the useLocalStorage hook to save search client side.
// useLocalStorage Hook to persist values client side
function useLocalStorage(key, initialValue) {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState(() => {
if (typeof window === "undefined") {
return initialValue;
}
try {
// Get from local storage by key
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// If error also return initialValue
console.log(error);
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore =
value instanceof Function ? value(storedValue) : value;
// Save state
setStoredValue(valueToStore);
// Save to local storage
if (typeof window !== "undefined") {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
} catch (error) {
// A more advanced implementation would handle the error case
console.log(error);
}
};
return [storedValue, setValue];
}
credit: Brandon Baars

React + TS: How to call a method from outside of a React Functional Component

Im wondering how I can call a method from outside of a React Functional Component. I wrote the function GetUsedLockers() which gets all the used lockers and returns amount. Now I want to call this function from another another component (OrgLocker.tsx) and display the data from the getUsedLockers() function there.
OrgLockerTables.tsx
const OrgLockerTables: React.FC = () => {
const lockerCall = 'lockers';
const [lockerData, setLockerData] = useState({
id: 0,
guid: "",
is_currently_claimable: false
}[""]);
useEffect(() => {
componentConsole().then((res) => {
setLockerData(res);
})
// eslint-disable-next-line
}, []);
if (!lockerData) return (<div>Loading...</div>);
//function to get all used lockers
function getUsedLockers() {
let amount = 0;
for (let i = 0; i < lockerData.length; i++) {
if (!lockerData.is_currently_claimable) {
amount++;
}
}
console.log('log from getusedlockers, amount: ', amount)
return (amount)
}
// function to get JSON data from the API
function componentConsole(): Promise<any> {
return new Promise<any>((resolve, reject) => {
http.getRequest('/' + lockerCall).then((res) => {
let data = res.data.data;
console.log('data:', data);
resolve(res.data.data);
}).catch((error) => {
console.log(error);
reject();
});
})
}
}
OrgLocker.tsx
import OrgLockerTables from '../tables/orgLockerTables';
const OrgLockers: React.FC = () => {
let lockerTable = new OrgLockerTables();
return (
<div className="main-div-org">
<p>Used</p>
<p>{lockerTable.getUsedLockers()}</p>
</div>
);
}
export default OrgLockers;
When trying to make a call to OrgLockerTables and storing it in the lockerTable let it gives the following error:
Expected 1-2 arguments, but got 0.ts(2554)
Any help would be greatly appreciated!
I've restructured everything making it more understandable, I hope you don't mind according to what I think you want the comment above.
locker-model.ts - The type for the particular data being called back is found
export type Locker = {
id: number;
guid: string;
isCurrentlyClaimable: boolean;
}
locker-business.ts - Where all the business logic is carried out, from the call for data to the calculation based on it
import { Locker } from "./locker-models";
const lockerCall = 'lockers';
const mockedData: Locker[] = [{
id: 0,
guid: "sample",
isCurrentlyClaimable: false,
},
{
id: 1,
guid: "sample2",
isCurrentlyClaimable: true,
},
{
id: 2,
guid: "sample3",
isCurrentlyClaimable: true,
}]
// Mocked function from your backend (componentConsole where you use lockerCall variable)
export const getLockersData = (): Promise<Locker[]> => Promise.resolve(mockedData);
export const getAmount = (lockers: Locker[]): number => {
let amount = 0;
!!lockers ?
lockers.filter(({isCurrentlyClaimable}) => { if(isCurrentlyClaimable) amount++ })
: 0;
return amount;
};
index.tsx - Here are both components that make the call to get the data and render the result you're looking for
import React, { Component } from 'react';
import { Locker } from './locker-models';
import { getLockersData, getAmount } from './locker-business';
import './style.css';
type OrgLockersProps = {
amount: number;
}
const OrgLockers: React.FC<OrgLockersProps> = ({ amount }) => {
return (
<div className="main-div-org">
<p>Lockers used:</p>
<p>{amount}</p>
</div>
);
}
type OrgLockerTableProps = {};
const OrgLockerTable : React.FC<OrgLockerTableProps> = props => {
const [lockerData, setLockerData] = React.useState<Locker[]>([]);
React.useEffect(() => {
getLockersData().then(response => setLockerData(response));
}, []);
const amount = getAmount(lockerData);
return (
<div>
<OrgLockers amount={amount} />
</div>
);
};
You can see the example here
You can create new .js file like Helpers.js and define export function with parameter it like that
export function getUsedLockers(lockerData) {
let amount = 0;
//Check your loop it can be like that
for (let i = 0; i < lockerData.length; i++) {
if (!lockerData[i].is_currently_claimable) {
amount++;
}
}
console.log('log from getusedlockers, amount: ', amount)
return (amount)
}
Then import it where do you want to use.
import {getUsedLockers} from "../Helpers";
And use it like that:
const amount = getUsedLockers(data);

Populating React dropdown asyncrhonously with Redux

Background
I'm attempting to create a dropdown that retrieves State Codes (AZ, WI, WY, etc.) from a backend API and then populates an on-screen dropdown with the values.
I have a React component that looks like this (an ellipsis representing code that I'm omitting for clarity):
Person.jsx
export class Person extends React.Component {
constructor(props) {
super(props);
...
this.props.getStateCodes();
}
render(){
...
<select
id="personState"
name="personState"
className="form-control dropDownStyle"
onChange={this.handleChange}
value={this.props.person.personState}
>
{this.props.stateCodes && this.props.stateCodes.map((option) => (
<option key={option.id} value={option.data}>{option.data}</option>
))
}
</select>
...
}
}
I then have Redux action creators, including an excerpt like this:
personContract.js
export const actionCreators = {
...
getStateCodes: () => async (dispatch) => {
getStateCodesResponse(dispatch);
},
...
export function getStateCodesResponse(dispatch) {
const endpoint = window.location.origin + '/Home/GetStateCodes';
fetch(endpoint, {
credentials: 'same-origin'
})
.then(function (response) {
if (!response.ok) {
const errors = ['Unable to retrieve state codes.'];
dispatch({ type: "SET_ERROR", errors: errors });
document.body.style.cursor = 'default';
return;
}
return response.json();
}).then(function (data) {
if (data !== undefined) {
const stateCodes = data.stateCodes;
// const stateCodes = result.PayLoad.StateCodes;
document.body.style.cursor = 'default';
dispatch({ type: 'STATECODES', stateCodes });
}
});
}
...
}
Then a reducer that includes:
Contract.js
const initialState ={
...
stateCodes: [],
...
};
export const reducer = (state, action) => {
...
if (action.type == "STATECODES"){
const stateCodes = action.stateCodes;
return {
...state,
errors: [],
stateCodes: stateCodes
}
}
...
}
Problem
Initially, I did not include {this.props.stateCodes && in the Person.jsx file. The issue then, was that I'd get an error that this.props.stateCodes was not defined. I added in {this.props.stateCodes &&, however, now it never runs this.props.stateCodes.map at all. It's almost as if I need to render() to run again after the State Codes have been retrieved, but I don't know how to accomplish that.

Categories