通过redux更改状态后如何更新React组件?

IT技术 javascript reactjs redux
2021-05-01 12:24:11

我正在学习 React 和 Redux,同时我决定制作带有按钮的网页,点击该按钮会改变状态。在按钮下方,我想在不同的组件中显示当前状态。虽然点击按钮改变了状态,但它并没有反映在组件中。这是我的代码:

应用程序.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>
      )
}

名称.js

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

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

export default Name

商店.js

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

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

动作.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' });
    }
}

减速器.js

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

当我单击按钮时, Name 组件内的文本不会改变。问题是什么?

2个回答

您需要按照 Redux 文档正确设置减速器和初始存储。

您缺少一个Provider,它将为您store的应用程序提供

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

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

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

现在,您的商店可用于您的组件。

您也reducer需要一个初始状态,并且您总是应该返回状态的更新副本。也就是说,不要直接更改状态,而是创建一个副本,更改它,然后返回该副本。

const initialState = {
  name: ""
};

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

export default reducer;

您可能已经注意到,我在您的商店中添加了一个中间件,这是因为在您的操作中访问当前减速器的状态时,通常采用这种方式。也就是说,我为此安装了 redux-thunk,所以在你的操作中,你可以有这样的东西:

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

现在,您的商店已提供给您的应用程序,您的减速器已完成并且您的操作已准备就绪,您可以将不同的组件连接到减速器。

您可以使用在高阶组件react-reduxconnect了点。例如,在您的Name组件中,我们可以通过将您的状态映射到组件的 props 来将要显示的名称连接到您的减速器:

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

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

export default connect(mapStateToProps)(Name);

这里的好处是,您还可以将connect高阶组件中的第一个参数留空,而只传递第二个参数,即调度函数。嗯,这就是你在你的App组件中要做的,你将它连接到changeName动作。

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);

现在,当 App 分派一个changeName动作时,您的减速器状态将被更新,并且连接到减速器状态的其他组件将重新渲染。

总结:试着把你的商店想象成一个空的糖果罐。你的罐子开始是空的,但不同的动作可能会改变罐子里的东西。最重要的是,房子里知道罐子在哪里的不同人可以去拿一些糖果。转化为您的问题,您的应用程序以一个空名称开头,并且您有一个设置名称的操作。通过连接到您的减速器知道在哪里可以找到该名称的组件将知道该名称何时更改并获得更新的名称。

最终代码可以在这里找到:

编辑警戒场-shfj7

您的名称组件重新渲染的唯一方式是它的 props 或状态更改,或者父组件是否重新渲染。在 redux 中进行更改不会自动执行此操作。为了查看状态的更改,您需要订阅这些更改。您可以自己执行此操作,但更好的解决方案是使用react-redux,它旨在将 React 组件连接到 redux 存储。

例如,您将向您的应用程序添加一个提供程序:

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>
  )
}

然后你会使用connect你的 Name 组件:

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)