'Why my component is not updated as the state from context was changed?
I'm newbie at React.
I have App.js(grandparent), CardWrapper.js(parent which has some styles), Card.js(child), AddressSearchComponent.js and Context.js which has a common state and reducer function.
I want all Cards updated newly when the address is changed.
Every component referencing a context is re-rendered when a state in the context is changed as I know.
But in my app CardWrapper was rendered just once at first
and not re-rendered a state was changed.
How can I make CardWrapper is re-rendered when list_for_cards is updated?
(Sorry for that my English is awful.)
App.js
import React from 'react';
import { ContextProvider } from './Context.js';
import AddressSearchComponentfrom './AddressSearchComponent';
import CardWrapper from './CardWrapper';
function App() {
return (
<>
<ContextProvider>
<AddressSearchComponent></AddressSearchComponent>
</ContextProvider>
<section>
<ContextProvider>
<CardWrapper></CardWrapper>
</ContextProvider>
</section>
</>
);
}
export default App;
AddressSearchComponent.js
import { useEffect, useContext } from 'react';
import axios from 'axios';
import { StateContext, DispatchContext } from './Context.js';
async function getData(...) {
const ret = await axios.get(...);
return ret.data;
}
function AddressSearchComponent() {
const state = useContext(StateContext);
const dispatch = useContext(DispatchContext);
window.state = state; // for debug
/* useEffect changing state options when selected country is changed */
/* useEffect changing city options when selected state is changed */
/* useEffect changing list_for_cards state when city is changed */
const onChange = ({name, value}) => {
dispatch({type: 'SET', name, value});
}
return (
<div>
/* a selectbox for country options */
/* a selectbox for state options */
/* a selectbox for city options * /
</div>
)
}
export default AddressSearchComponent;
Context.js
import React, { useReducer } from 'react';
const initialState = {
currentCountry: '',
countryList: [],
currentState: '',
stateList:[],
currentCity: '',
cityList: [],
list_for_cards: []
}
function reducer(state, action) {
switch (action.type) {
case 'SET':
return {
...state,
[action.name]: action.value
}
default:
return state;
}
}
export const StateContext = React.createContext();
export const DispatchContext = React.createContext();
export function ContextProvider({children}) {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<StateContext.Provider value={state}>
<DispatchContext.Provider value={dispatch}>
{children}
</DispatchContext.Provider>
</StateContext.Provider>
)
}
CardWrapper.js
import { useContext } from 'react';
import Card from "./Card";
import { StateContext } from './Context';
function CardWrapper() {
const { list_for_cards } = useContext(StateContext);
return (
<>
{
list_for_cards.map(item=>
<Card item={item}></Card>
)
}
</>
)
}
export default CardWrapper;
Solution 1:[1]
If I understand correctly, In AddressSearchComponent you only want to update state that comes from select boxes (so selected country, state and city - in your state they). But you need to add these new values to the list_for_cards as well, and you have to update your list state in the reducer.
Solution 2:[2]
Actually, there is a minor problem with your app.js
You are wrapping <AddressSearchComponent/> & <CardWrapper /> with <ContextProvider /> but in wrong way. Both of your compoent should inside one warpper.
It should be wrapped like the following.
import React from 'react';
import { ContextProvider } from './Context';
import AddressSearchComponentfrom './AddressSearchComponent';
import CardWrapper from './CardWrapper';
function App() {
return (
<>
<ContextProvider>
<AddressSearchComponent />
<CardWrapper />
</ContextProvider>
</>
);
}
export default App;
https://reactjs.org/docs/context.html#updating-context-from-a-nested-component
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | a_dahlin |
| Solution 2 | Sodhi saab |
