0

I have a user model that looks like this:

{
    "name": "Sun12",
    "role": "1",
    "email": "[email protected]",
    "password": "test123",
    "about": "This is a description of me.",
    "skills": ["Acting", "Music", "Art", "English Literature"],
    "studying": "Mind Control"
}

I want to create a form that will capture the above users information.

The skills field in the user schema is arbitrarily long - I want users to be able to add as many skills as they like.

How can I dynamically render text input fields, and send each of the inputs to those dynamically rendered fields to the skills array?

Here is my entire Signup.js file:

// users Signin

import React, {useState} from 'react';
import Layout from '../core/Layout';
import {API} from '../config';

const Signup = () => {

  const [values, setValues] = useState({
    name: '',
    email: '',
    password: '',
    studying: '',
    skills: [],
    error: '',
    success: ''
  });

  const {name, email, password, studying} = values;


  const signup = (user) => {
    fetch(`${API}/signup`, {
      method: "POST",
      headers: {
        Accept: 'application/json',
        "Content-Type": "application/json"
      },
      body: JSON.stringify(user)
    })
    .then(response => {
      return response.json();
    })
    .catch(err => {
      console.log(err);
    });
  };

  const clickSubmit = event => {
    event.preventDefault();
    signup({name, email, password, studying});
  };

  const handleChange = name => event => {
    setValues({...values, error: false, [name]: event.target.value});
  };



  const signUpForm = () => (
    <form>
        <div className="form-group">
            <label className="text-muted">Name</label>
            <input onChange={handleChange('name')} type="text" className ="form-control" />
        </div>

        <div className="form-group">
            <label className="text-muted">Email</label>
            <input onChange={handleChange('email')} type="email" className ="form-control" />
        </div>

        <div className="form-group">
            <label className="text-muted">Password</label>
            <input onChange={handleChange('password')} type="password" className="form-control" />
        </div>

        <div className="form-group">
            <label className="text-muted">Studying</label>
            <input onChange={handleChange('studying')} type="text" className ="form-control" />
        </div>

        <div>
            <div>{createInputs()}</div>
            <button onClick={addSkill}>Add</button>
        </div>

        <button onClick={clickSubmit} className="btn btn-primary">
          Sign Up
        </button>

    </form>
  );


  return(
  <Layout 
    title="Signup" 
    description="Join today."
    className="container col-md-8 offset-md-2">
      {signUpForm()}
      {JSON.stringify(values)}
  </Layout>
  );
};

export default Signup;

1 Answer 1

3

You just need to iterate over the array with .map() to render an input corresponding to each skill. Then set-up some event-handlers that let you update that skill and create new skills by adding another item into the array.

See working sandbox: https://codesandbox.io/s/festive-bhaskara-gdxwm

import React, { useState, useEffect } from "react";

const User = ({ data }) => {
  const [user, setUser] = useState({
    name: "",
    role: "",
    email: "",
    password: "",
    about: "",
    skills: [],
    studying: ""
  });

  const createInputs = () => {
    return user.skills.map((skill, idx) => {
      return (
        <div>
          <input value={skill} onChange={e => updateSkill(e, idx)} />
        </div>
      );
    });
  };

  const updateSkill = (e, index) => {
    const userCopy = { ...user };
    userCopy.skills[index] = e.target.value;
    setUser(userCopy);
  };

  const removeSkill = index => {
    const userCopy = { ...user };
    const userCopySkills = [...userCopy.skills];

    userCopySkills.splice(index, 1);

    setUser({
      ...userCopy,
      skills: [...userCopySkills]
    });
  };

  const addSkill = () => {
    setUser(prevState => {
      return {
        ...prevState.user,
        skills: [...prevState.skills, ""]
      };
    });
  };

  useEffect(() => {
    console.log(user);
  }, [user]);

  return (
    <div>
      <div>{createInputs()}</div>
      <button onClick={addSkill}>Add</button>
    </div>
  );
};

export default User;

I threw in the useEffect() there just to show you that the skills array is getting updated. You can take it off if you'd like.

Sign up to request clarification or add additional context in comments.

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.