admin管理员组

文章数量:1320670

I was learning React and Redux and while doing that I decided to make webpage with a button which on clicking would change the state. Below the button I wanted to display the current state in a different ponent. Though the button on clicking changes the state, but it is not getting reflected in the ponent. Here is my code:

App.js

import React from 'react'
import Name from './Name'
import {changeName} from './Action'; 

export default function App () {  
      return (
          <div>
            <button onClick={changeName}>Click me</button>
            <Name />
          </div>
      )
}

Name.js

import React from 'react'
import {store} from './Store'

function Name(props) {
    return (
        <div>           
            My name is: {store.getState()}
        </div>
    )
}

export default Name

Store.js

import { createStore } from 'redux';
import {reducer} from './Reducer';

export const store = createStore(reducer, 'Tarun');

Action.js

import {store} from './Store';

export const changeName = () => {
    if (store.getState() === "Tarun"){
        store.dispatch({ type: 'name', payload: 'Subhash' });
    }
    else{
        store.dispatch({ type: 'name', payload: 'Tarun' });
    }
}

Reducer.js

export const reducer = function(state, action) {
    if (action.type === 'name') {
      return action.payload;
    }
    return state;
};

When I click the button, The text inside the Name ponent does not change. What is the issue?

I was learning React and Redux and while doing that I decided to make webpage with a button which on clicking would change the state. Below the button I wanted to display the current state in a different ponent. Though the button on clicking changes the state, but it is not getting reflected in the ponent. Here is my code:

App.js

import React from 'react'
import Name from './Name'
import {changeName} from './Action'; 

export default function App () {  
      return (
          <div>
            <button onClick={changeName}>Click me</button>
            <Name />
          </div>
      )
}

Name.js

import React from 'react'
import {store} from './Store'

function Name(props) {
    return (
        <div>           
            My name is: {store.getState()}
        </div>
    )
}

export default Name

Store.js

import { createStore } from 'redux';
import {reducer} from './Reducer';

export const store = createStore(reducer, 'Tarun');

Action.js

import {store} from './Store';

export const changeName = () => {
    if (store.getState() === "Tarun"){
        store.dispatch({ type: 'name', payload: 'Subhash' });
    }
    else{
        store.dispatch({ type: 'name', payload: 'Tarun' });
    }
}

Reducer.js

export const reducer = function(state, action) {
    if (action.type === 'name') {
      return action.payload;
    }
    return state;
};

When I click the button, The text inside the Name ponent does not change. What is the issue?

Share Improve this question asked Oct 5, 2019 at 15:23 Dreaded HarvesterDreaded Harvester 1,5479 gold badges26 silver badges44 bronze badges 0
Add a ment  | 

2 Answers 2

Reset to default 4

You need to set up your reducer and initial store properly following the Redux documentation.

You're missing a Provider, which will provide your store to your application.

const store = createStore(reducer, applyMiddleware(thunk));

const rootElement = document.getElementById("root");

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  rootElement
);

Now, your store is available to your ponents.

Your reducer needs an initial state too and you're always supposed to return an updated copy of your state. That said, don't change the state directly, but make a copy, change it, then return that copy.

const initialState = {
  name: ""
};

const reducer = function(state = initialState, action) {
  if (action.type === "name") {
    return { ...state, name: action.payload };
  } else {
    return state;
  }
};

export default reducer;

You might have noticed that I added a middleware to your store, and that's because it's usually the way to go when accessing your current reducer's state in your actions. That said, I installed redux-thunk for that, so in your action, you can have something like this:

export const changeName = () => {
  return (dispatch, getState) => {
    if (getState().name === "Tarun") {
      dispatch({ type: "name", payload: "Subhash" });
    } else {
      dispatch({ type: "name", payload: "Tarun" });
    }
  };
};

Now, with your store being provided to your app, your reducer being done and your actions being ready to go, you can connect different ponents to your reducer.

You use the high order ponent in react-redux called connect for that. For example, in your Name ponent, we can connect the name to be displayed to your reducer by mapping your state to the ponent's props:

function Name(props) {
  return <div>My name is: {props.name}</div>;
}

const mapStateToProps = state => {
  return {
    name: state.name
  };
};

export default connect(mapStateToProps)(Name);

The nice thing here is that you can also leave the first parameter in the connect high order ponent empty and just pass the second, which would be the dispatch functions. Well, that's what you would do in your App ponent, you would connect it to the changeName action.

function App(props) {
  return (
    <div>
      <button onClick={props.changeName}>Click me</button>
      <Name />
    </div>
  );
}

const mapDispatchToProps = dispatch => {
  return {
    changeName: () => dispatch(changeName())
  };
};

export default connect(
  null,
  mapDispatchToProps
)(App);

Now, when App dispatches a changeName action, your reducer state will be updated and the other ponents that are connected to the reducer's state will re-render.

Summary: Try to think of your store as an empty jar of candies. Your jar starts empty, but different actions could change what's inside the jar. On top of that, different people in the house that know where the jar is can go get some candy. Translating to your problem, your app begins with an empty name and you have an action that sets up a name. The ponents that know where to find that name by being connected to your reducer will know when that name changes and will get the updated name.

The final code can be found here:

The only way your name ponent will rerender is its props or state change, or if a parent ponent rerenders. Making a change in redux will not automatically do this. In order to see changes to the state, you'd need to subscribe to those changes. You could do this yourself, but a far better solution is to use react-redux, which is designed for connecting react ponents to redux stores.

For example, you'd add a provider to your app:

import { Provider } from 'react-redux';
import { store } from './Store'

export default function App () {  
  return (
    <Provider store={store}>
      <div>
        <button onClick={changeName}>Click me</button>
        <Name />
      </div>
    </Provider>
  )
}

And then you'd use connect with your Name ponent:

import { connect } from 'react-redux';
function Name(props) {
  return (
    <div>           
      My name is: {props.name}
    </div>
  )
}

const mapStateToProps = (state) => {
  return { name: state };
}

export default connect(mapStateToProps)(Name)

本文标签: javascriptHow to update React component after changing state through reduxStack Overflow