0

I've created the reducer and using it to change the state of my store. but as you can see in App.js whenever I click on button and update the state. it updates. I can see it in console. but component does not update. as you can see I have list of tracks there it is not updating. and if I make any changes to code because of that the component re-render I can see the new state after that. why is it not rendering automatically whenever the state updates.

Action

import * as actions from './actionTypes'

export const trackAdded = (title, artist, audioSrc, img) => {
    return {
        type: actions.TRACK_ADDED,
        payload: {
            title,
            artist,
            audioSrc,
            img
        }
    }
}

Reducer

import * as actions from './actionTypes'

export default function reducer(state = [], action) {
    switch (action.type) {
        case actions.TRACK_ADDED:
            return [
                ...state,
                {
                    title: action.payload.title,
                    artist: action.payload.artist,
                    audioSrc: action.payload.audioSrc,
                    img: action.payload.img
                }
            ]

        default:
            return state
    }
}

App.js

import './App.css';
import store from './store'
import { trackAdded } from './actions'

function App() {
  const add = (title) => {
    store.dispatch(trackAdded(title, "Taylor Swift", "src", "image"))
    console.log(store.getState())
  }
  
  return (
    <div className="App">
      {store.getState().map((track, track_id) => {
        return (
          <li key={track_id}>{track.title}</li>
        )
      })}
      <button onClick={() => { add("Shake It Off") }}>Add Track</button>

    </div>
  );
}

export default App;
Amisha Mundra
  • 47
  • 1
  • 9
  • 2
    Try to use react-redux which helps to read and update the store from your components with optimised hooks . – Shyam Jun 03 '21 at 18:53
  • You should use [react-redux](https://react-redux.js.org/introduction/getting-started), wrap your app in a [provider](https://react-redux.js.org/introduction/getting-started#provider), use the [useSelector and useDispatch](https://react-redux.js.org/introduction/getting-started#hooks) hooks in your component. – HMR Jun 03 '21 at 19:05

2 Answers2

2

The component will not update because the store.getState() inside of <div className="App"> will only run once when the component is called. There is no logic that exists that tells the component to rerun the store.getState(). If you want the component to receive updates when the store's state changes, you need to connect it to the store using react-redux's connect function or a useSelector hook.

As an example, if using the connect function, you can map the redux state to a react component's props. So if the component's props change, then the component will "react" to it's props changing. The mapping of redux's state to the components props happens in the mapStateToProps function, returning a prop tracks that is mapped to the component. Otherwise there is no reason for the component to update. Also note: in the example below, the store is connected to React through a Provider component, providing the store to child components that wish to connect to it.

import { Provider, connect } from 'react-redux'

import './App.css';
import store from './store'
import { trackAdded } from './actions'

function App(props) {
  const add = (title) => {
    store.dispatch(trackAdded(title, "Taylor Swift", "src", "image"))
    console.log(store.getState())
  }
  
  return (
    <Provider store={store}>
      <div className="App">
        {props.tracks.map((track, track_id) => {
          return (
            <li key={track_id}>{track.title}</li>
          )
        })}
        <button onClick={() => { add("Shake It Off") }}>Add Track</button>
      </div>
    </Provider>
  );
}

const mapStateToProps = (state) => {
  const tracks = state
  return { tracks }
}

export default connect(mapStateToProps)(App);

Having said that, if you go the connect route, you might want to add a mapDispatchToProps function to the connect so you dont pass around the store everywhere. You can find that info in the redux docs, but that would be an answer to a different question.

Chan Youn
  • 782
  • 7
  • 10
-1

This is happening because your component does not know that store has been updated, you can use something like this

useEffect(() => {
  this.artistList = store.getState();
}, [store.getState()]); // kind of watcher of store.getState()

but this is definitely not recommended. You would want to use useSelector() from react-redux, which is much concise and recommended way to doing it.

icebug
  • 193
  • 4