1

I'm new to redux so just trying to apply redux to a very simple app. It just toggles the word whenever the button is clicked. But how should I dispatch my handleClick function except the action? For now nothing happens when I click the button.

App.js

import React, { Component } from "react";
import { connect } from 'react-redux'; 

import MyButton from "./MyButton";
import { handleClick } from "./actions"; 

import "./styles.css";

class App extends Component {
  handleClick = () => {
    if (this.state.text === "initial text") {
      this.setState({ text: "" });
    } else {
      this.setState({ text: "initial text" });
    }
  }

  render() {
    return (
      <div className="App">
        <MyButton onClick={()=>this.props.handleClick('hi')} />
        <p>{this.props.text}</p>
      </div>
    );
  }
}

const mapStateToProps = state => ({
    text: state.text
})

const mapDispatchToProps = dispatch => ({
  handleClick: () => dispatch(handleClick)
})

export default connect(mapStateToProps, mapDispatchToProps)(App)

MyButton.js

import React, { Component } from "react";

class MyButton extends Component {
  render() {
    return <button onClick={this.props.onClick}>
            Click Me!
            </button>;
  }
}

export default MyButton;

actions.js

export const handleClick = text => ({
  type: "test_action",
  payload: { ...text }
});

reducers.js

export const reducer = (state = {text:'initial_text'}, action) => {
  if(action.type === 'test_action') {
    return Object.assign({}, state, action.payload)
  }
  return state; 
}

index.js

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from 'react-redux'; 
import { createStore } from 'redux'; 

import { reducer } from "./reducers"; 
import App from "./App"; 

import "./styles.css";

const store = createStore(reducer); 

const rootElement = document.getElementById("root");
ReactDOM.render(<Provider store={store}><App /></Provider>, rootElement);

2 Answers 2

1

You should pass an argument to your handleClick function:

const mapDispatchToProps = dispatch => ({
  handleClick: (text) => dispatch(handleClick(text))
})

or just:

const mapDispatchToProps = { handleClick }

Your action is spreading a string inside an object, you should use it as-is:

export const handleClick = text => ({
  type: "test_action",
  payload: text
});

And your reducer is setting the whole state, instead of just the text property. You can avoid the confusion by splitting then recomining the reducer:

import { combineReducers } from 'redux'

export const text = (state='', action) => {
  if(action.type === 'test_action') {
    return action.payload;
  }
  return state; 
}

export const reducer = combineReducers({
  text
})
Sign up to request clarification or add additional context in comments.

3 Comments

object.assign should copy the entire state so, that should not be a problem
That would not be a problem if action.payload had a text property, but it doesn't
Also doing this { ...text } with text being a string will return the text splitted to an array of letters
1

The problem is that the mapDispatchToProps handleClick prop in the above code does not accept arguments

const mapDispatchToProps = dispatch => ({
  handleClick: (val) => dispatch(handleClick(val)) // update here so that the 'hi' text is passed to the action creator
})

<MyButton onClick={()=>this.props.handleClick('hi')} />

Update

The state is not updated correctly

return Object.assign({}, state, { text: action.payload }) //pass an object and not just the value

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.