In a sample mini app I have index.js which renders <App />
(with ReactDOM.render method). And <App />
is:
import { useReducer } from 'react';
import AppContext, { defaultAppState } from './store/AppContext';
import AppReducer from './store/AppReducer';
import CitiesList from './components/CitiesList';
import AddCity from './components/AddCity';
export default function App() {
const [appState, dispatch] = useReducer(AppReducer, defaultAppState);
return (
<AppContext.Provider value={[ appState, dispatch ]}>
<CitiesList />
<AddCity />
</AppContext.Provider>
);
}
The context is defined in a file like this (AppContext.js):
import React from 'react';
export const defaultAppState = {
cities: [
{name: 'CityA', temperature: 20},
{name: 'CityB', temperature: 12},
],
};
export default React.createContext(
defaultAppState
);
And the reducer is this one (AppReducer.js):
import { defaultAppState } from './AppContext';
import * as ACTIONS from './Actions';
const AppReducer = (state = defaultAppState, action) => {
switch(action.type) {
case ACTIONS.ADD_CITY:
const newCities = state.cities.concat([action.payload]);
return { ...state, cities: newCities };
default:
return state;
}
}
export default AppReducer;
In <AddCity />
component I'm successfully triggering dispatch
and update the state in the reducer. (Placed console.log just before the return
and saw that it's what the new state is supposed to be.) However, this does not trigger re-rendering and <CitiesList />
doesn't reflect any change - it always shows the default state.
Any idea what I'm doing wrong?
=====
EDIT:
Adding the code of <CitiesList />
:
import React, { useContext } from 'react';
import AppContext from '../store/AppContext';
export default function CitiesList() {
const [appState, dispatch] = useContext(AppContext);
const { cities } = appState;
return (
<>
<h1>Cities ({cities.length})</h1>
{cities.length > 0 &&
// Looping the cities array and showing the actual cities ..
}
</>
);
}
Adding the code of <AddCity />
as well:
import { useState, useReducer } from 'react';
import AppReducer from '../store/AppReducer';
import { ADD_CITY } from '../store/Actions';
export default function AddCity() {
const [appReducer, dispatch] = useReducer(AppReducer);
const [name, setName] = useState('');
const onButtonClick = e => {
const newCityData = { name: name, temperature: 18 };
dispatch({type: ADD_CITY, payload: newCityData});
setName('');
};
return (
<>
<input value={name} onChange={e => setName(e.target.value)} />
<br/>
<button onClick={onButtonClick}>Add city</button>
</>
);
}