How to pass in the state to the dispatch action if using useState instead of this.state in react?

Viewed 797

I am a beginner starting out in react and having difficulties in state management while working with react-redux and useState. In the below code I am basically following a tutorial which passes in the this.state to the dispatch action createProject in the handleSubmit function as seen below.

class CreateProject extends Component {
  state = {
    title: '',
    content: ''
  }
  handleChange = (e) => {
    this.setState({
      [e.target.id]: e.target.value
    })
  }
  handleSubmit = (e) => {
    e.preventDefault();
    // console.log(this.state);
    this.props.createProject(this.state);
  }
  render() {
    return (
      <div className="container">
        <form className="white" onSubmit={this.handleSubmit}>
          <h5 className="grey-text text-darken-3">Create a New Project</h5>
          <div className="input-field">
            <input type="text" id='title' onChange={this.handleChange} />
            <label htmlFor="title">Project Title</label>
          </div>
          <div className="input-field">
            <textarea id="content" className="materialize-textarea" onChange={this.handleChange}></textarea>
            <label htmlFor="content">Project Content</label>
          </div>
          <div className="input-field">
            <button className="btn pink lighten-1">Create</button>
          </div>
        </form>
      </div>
    )
  }
}

const mapDispatchToProps = dispatch => {
  return {
    createProject: (project) => dispatch(createProject(project))
  }
}

export default connect(null, mapDispatchToProps)(CreateProject)

Now, instead of using Class component I am using the functional component and using the useState hook. in the handleSubmit function how can I pass the state to the this.props.createProject() as this.props is not defined in-case of functional component and how to pass the state in place of this.state, will it be the projectinfo which stores the state or something else, I'm confused.

TLDR; I want to rewrite the this.props.createProject(this.state) line from the perspective of useState hook.

Below is the code I have written:

const CreateProject = () => {

    const [title, setTitle] = useState('');
    const [content, setContent] = useState('');


    const handleSubmit = (e) => {
        e.preventDefault();

        const projectinfo = { title, content }

        this.props.createProject(projectinfo);

    }
    return(
        <div className="container">
            <form onSubmit={handleSubmit} className="white">
                <h5 className="grey-text text-darken-3">Create Task</h5>
                <div className="input-field">
                    <label htmlFor="title">Title</label>
                    <input type="text" value={title} id="title" onChange={(e) => setTitle(e.target.value)} />
                </div>
                <div className="input-field">
                    <label htmlFor="content">Content</label>
                    <textarea id="content" className="materialize-textarea" onChange={(e) => setContent(e.target.value)}></textarea>
                   
                </div>
                <button className="btn pink lighten-1 z-depth-0">Create</button>
            </form>
        </div>
    );

}

const mapDispatchToProps  = (dispatch) =>{
    return{
        createProject: (project) => dispatch(createProject(project)),
    };
}

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

Any help or clues to understand this would be appreciated. Thank you!

2 Answers

Just want to add some way to do it using react hooks (specifically useDispatch).

With hooks, you don't need to use connect() and mapDispatchToProps. Instead, you can do it like this:

const CreateProject = () => {
  const dispatch = useDispatch();
  const [title, setTitle] = useState('');
  const [content, setContent] = useState('');

  const handleSubmit = (e) => {
      e.preventDefault();

      const projectinfo = { title, content }

      // Use dispatch here
      dispatch(createProject(projectinfo));
  }

  return(
    <div className="container">
        <form onSubmit={handleSubmit} className="white">
            <h5 className="grey-text text-darken-3">Create Task</h5>
            <div className="input-field">
                <label htmlFor="title">Title</label>
                <input type="text" value={title} id="title" onChange={(e) => setTitle(e.target.value)} />
            </div>
            <div className="input-field">
                <label htmlFor="content">Content</label>
                <textarea id="content" className="materialize-textarea" onChange={(e) => setContent(e.target.value)}></textarea>
               
            </div>
            <button className="btn pink lighten-1 z-depth-0">Create</button>
        </form>
    </div>
  );
}

export default CreateProject

createProject() is your action creators.

You can read more about useDispatch here: https://react-redux.js.org/api/hooks#usedispatch

Your dispatch isn't working because you're trying to access it via this.props. Assuming that createProject call inside the dispatch call in mapDispatchToProps is valid and there is a createProject function available in the scope of that file, what you need to do is this:

const CreateProject = (props) => { // Get props from the parameter.

    const [title, setTitle] = useState('');
    const [content, setContent] = useState('');


    const handleSubmit = (e) => {
        e.preventDefault();

        const projectinfo = { title, content }

       props.createProject(projectinfo); // Replace this.props and use props

    }
    return(
        <div className="container">
            <form onSubmit={handleSubmit} className="white">
                <h5 className="grey-text text-darken-3">Create Task</h5>
                <div className="input-field">
                    <label htmlFor="title">Title</label>
                    <input type="text" value={title} id="title" onChange={(e) => setTitle(e.target.value)} />
                </div>
                <div className="input-field">
                    <label htmlFor="content">Content</label>
                    <textarea id="content" className="materialize-textarea" onChange={(e) => setContent(e.target.value)}></textarea>
                   
                </div>
                <button className="btn pink lighten-1 z-depth-0">Create</button>
            </form>
        </div>
    );

}

const mapDispatchToProps  = (dispatch) =>{
    return{
        createProject: (project) => dispatch(createProject(project)),
    };
}

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

This would work. I hope this answered and solved your issue.

Related