简体   繁体   English

React Redux:获取道具和更新状态

[英]React Redux: Getting Props And Updating State

I am trying out React/Redux/JS for the first time. 我是第一次尝试React / Redux / JS。 I am a little confused about setting state in component vs letting redux update it. 关于在组件中设置状态与让redux更新它有点困惑。

I want to click a button to set the lightOn to true and have the updated this.props.lightOn value display. 我想单击一个按钮将lightOn设置为true并显示更新的this.props.lightOn值。 I am missing something fundamental but not sure what. 我遗漏了一些根本但不确定的东西。

action: 行动:

export const setLight = lightStatus => dispatch => {
  const res = lightStatus;
  console.log(res); // => true on click

  dispatch({ type: SET_LIGHT, payload: res });
};

In the component, {this.props.onLight} is undefined so I am not updating state correctly: 在组件中,{this.props.onLight}未定义,因此我没有正确更新状态:

import React, { Component } from 'react';
import { connect } from 'react-redux';
//import * as actions from '../actions';
import { setLight } from '../actions';
import { bindActionCreators } from 'redux';

class Light extends Component {
  render() {

    return (
      <div>
        Light Status: {this.props.lightOn}
        <button
          className="btn"
          onClick={() => this.props.setLight(true)}
        >
          Set Light!
        </button>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    lightOn: state.lightOn
  };
}

function mapDispatchToProps(dispatch) {
  //whenever selectBook is called the result should be passed to all of our reducers
  return bindActionCreators({ setLight: setLight }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Light);

the reducer (updated with spread operator): reducer(用spread运算符更新):

import { SET_LIGHT } from '../actions/types';

export default function(state = [], action) {
  switch (action.type) {
    case SET_LIGHT:
     return { ...state, lightOn: action.payload };
    default:
      return state;
  }
}

How about set it as a state instead of pass direct to the function ? 如何将其设置为状态而不是直接传递给函数? First binding it inside Constructor and then on click setState to true ? 首先将它绑定在Constructor中,然后单击setState为true?

constructor(props) {
super(props);
this.state:{lightOn: false};
this.OnClick = this.OnClick.bind(this);
}

onClick(event) {
this.setState({lightOn: true});
}

onClick ={this.onClick()}

As you are using redux , you can do it this way by returning a fresh state instead 当您使用redux时,您可以通过返回一个新状态来这样做

   return {...state, action.payload };

How it works? 这个怎么运作? Through connect you can inject props that are used to control redux state and bind it to the component. 通过connect您可以注入用于控制redux状态并将其绑定到组件的props。 For example: 例如:

class SomeComponent extends React.Component {
    componentWillMount() {
        this.props.sendSomething('someName');
    }

    render() {
        return (
            <div>{this.props.stateProp}</div>
        )
    }
}

const mapStateToProps = state = ({
    stateProp: state.someReduxState,
});

const mapDispatchToProps = dispatch => ({
    sendSomething: (name) => dispatch(someActionCreator(name)),
});

const ConnectedComponent = connect(
    mapStateToProps,
    mapDispatchToProps,
)(SomeComponent);

In given example you are binding someReduxState part of state to stateProp , which is injected into component. 在给定的示例中,您将someReduxState状态的一部分绑定到stateProp ,后者将注入到组件中。 You are injecting method ( sendSomething ) that will dispatch and action in redux. 您正在注入将在redux中调度和操作的方法( sendSomething )。 If component relays on displaying part of redux state, it will be updated each time redux state changes, because props that are injected to component will change. 如果组件在显示redux状态的一部分时继续,则每次redux状态更改时都会更新,因为注入组件的props会发生变化。 You can find more in official Redux documentation here , or you can watch free tutorial on egghead here . 您可以在此处找到官方Redux文档中的更多内容,或者您​​可以在此处观看有关egghead的免费教程。

You are not returning a new state here 你没有回到这里的新州

export default function(state = [], action) {
  switch (action.type) {
    case SET_LIGHT:
      return action.payload;
    default:
      return state;
  }
}

You're directly returning action.payload which is simply lightStatus 你直接返回action.payload ,它只是lightStatus

Which means you can't access state.lightOn in your mapStateToProps 这意味着您无法访问state.lightOn中的mapStateToProps

Your should be doing 你应该这样做

 case SET_LIGHT:
              return {
                ...state,
                lightOn: action.payload,
              };

Or directly 或直接

case SET_LIGHT:
                  return {
                    ...state,
                    action.payload,
                  };

This way the entire state is not lost and its not directly mutating the state. 这样整个州不会丢失,也不会直接改变国家。 Here i am using the object spread operator instead of Object.assign for the sake of simpicity. 为了简单起见,我在这里使用对象扩展运算符而不是Object.assign

the wrong on the reducer, the reducer should return the state object with lightOn key, but you return payload value, and this is the issue. reducer上的错误,reducer应该使用lightOn键返回状态对象,但是返回有效负载值,这就是问题所在。 your reducer should return lightOn with payload value like this. 你的reducer应该像这样返回带有效负载值的lightOn。

import { SET_LIGHT } from '../actions/types';

export default function(state = {}, action) {
  switch (action.type) {
    case SET_LIGHT:
      return {...state, action.payload}
    default:
      return state;
  }
}

Instead of setting state with array I am now setting with object. 我没有使用数组设置状态,而是使用object进行设置。 I guess I was putting lightOn object in light array which was making it inaccessible. 我想我将lightOn对象放在光阵列中,这使得它无法访问。

action: 行动:

export const setLight = lightStatus => dispatch => {
  dispatch({ type: SET_LIGHT, payload: lightStatus });
};

reducer: 减速器:

import { SET_LIGHT } from '../actions/types';

export default function(state = { on: false }, action) {
  console.log('state ', state);
  switch (action.type) {
    case SET_LIGHT:
      return { ...state, on: action.payload };
    default:
      return state;
  }
}

the component: 组件:

import React, { Component } from 'react';
import { connect } from 'react-redux';
//import * as actions from '../actions';
import { setLight } from '../actions';
import { bindActionCreators } from 'redux';

class Light extends Component {
  render() {
    return (
      <div>
        Light On: {this.props.light.on.toString()}
        <button
          className="btn"
          onClick={() => this.props.setLight(!this.props.light.on)}
        >
          Set Light!
        </button>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return { light: state.light };
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators({ setLight: setLight }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Light);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM