Home > Software design >  How do I convert this code into a functional component?
How do I convert this code into a functional component?

Time:10-24

I need to convert this code into a functional component. The code is regarding a form with multiple input text fields but one handler. I Basically need to get a better understanding of how hooks and functional components work.

This is the class component that I wan't to transform into a functional component.

    export class Form extends React.Component {
      constructor(props) {
        super(props);
    
        this.state = {
          data: {
            career: "",
            experience: "",
            additionalInformation: ""
          }
        };
    
        this.handleTextareaChange = this.handleTextareaChange.bind(this);
      }
    
      handleTextareaChange(event) {
        const { data } = this.state;
        data[event.target.name] = event.target.value;
        this.setState({
          data
        });
      }
    
      render() {
        return (
          <form>
            <ul>
              <li>
                <Textbox
                  labelText="Write your career "
                  value={this.state.data.career}
                  placeholder="e.g. extra information"
                  name="career"
                  onChange={this.handleTextareaChange}
                />
                <span>{this.state.data.career}</span>
              </li>
              <li>
                <Textbox
                  labelText="Write your experience"
                  value={this.state.data.experience}
                  placeholder="e.g. extra information"
                  name="experience"
                  onChange={this.handleTextareaChange}
                />
                <span>{this.state.data.experience}</span>
              </li>
              <li>
                <Textbox
                  labelText="Additional information"
                  value={this.state.data.additionalInformation}
                  placeholder="e.g. extra information"
                  name="additionalInformation"
                  onChange={this.handleTextareaChange}
                />
                <span>{this.state.data.additionalInformation}</span>
              </li>
            </ul>
          </form>
        );
      }
    }
   
    ```

CodePudding user response:

getting the first understanding of functional components can be confusing. I quickly rewrote your function so you can have a basic understanding of hooks. I highly suggest that you read the React hook documentation.

https://reactjs.org/docs/hooks-intro.html

const Form = () => {
  const [data, setDate] = useState({
    career: '',
    experience: '',
    additionalInformation: '',
  });

  const handleTextareaChange = (event) => {
    const newData = { ...data };
    newData[event.target.name] = event.target.value;
    setDate({
      newData,
    });
  };

  return (
    <form>
      <ul>
        <li>
          <Textbox
            labelText="Write your career "
            value={data.career}
            placeholder="e.g. extra information"
            name="career"
            onChange={handleTextareaChange}
          />
          <span>{data.career}</span>
        </li>
        <li>
          <Textbox
            labelText="Write your experience"
            value={data.experience}
            placeholder="e.g. extra information"
            name="experience"
            onChange={handleTextareaChange}
          />
          <span>{data.experience}</span>
        </li>
        <li>
          <Textbox
            labelText="Additional information"
            value={data.additionalInformation}
            placeholder="e.g. extra information"
            name="additionalInformation"
            onChange={handleTextareaChange}
          />
          <span>{data.additionalInformation}</span>
        </li>
      </ul>
    </form>
  );
};

export default Form;

CodePudding user response:

  1. First you need to use useState hook in functional component instead of this.state:

    const [state,setState]=React.useState({data: {
            career: "doctor",
            experience: "",
            additionalInformation: ""
          }})
    
  2. this keyword is not acceptable in functional components, so you need to remove it.

  3. Finally with just return keyword you can get your component and render it.

Here's the functional component:

export const Form : React.FC = (props)=> {
  const [state,setState]=React.useState({data: {
    career: "doctor",
    experience: "",
    additionalInformation: ""
  }})

  const handleTextareaChange = (event)=> {
    const { data } = state;
    data[event.target.name] = event.target.value;
    setState({
      data
    });
  }


    return (
      <form>
        <ul>
          <li>
            <Textbox
              labelText="Write your career "
              value={state.data.career}
              placeholder="e.g. extra information"
              name="career"
              onChange={handleTextareaChange}
            />
            <span>{state.data.career}</span>
          </li>
          <li>
            <Textbox
              labelText="Write your experience"
              value={state.data.experience}
              placeholder="e.g. extra information"
              name="experience"
              onChange={handleTextareaChange}
            />
            <span>{state.data.experience}</span>
          </li>
          <li>
            <Textbox
              labelText="Additional information"
              value={state.data.additionalInformation}
              placeholder="e.g. extra information"
              name="additionalInformation"
              onChange={handleTextareaChange}
            />
            <span>{state.data.additionalInformation}</span>
          </li>
        </ul>
      </form>
    );
}

CodePudding user response:

People here had really good answers, But here is what I would do - if you don't mind spliting data keys into 3 different variables:

const Form = (props) => {
    const [career, setCareer] = useState("");
    const [experience, setExperience] = useState("");
    const [additionalInformation, setAdditionalInformation] = useState("");

        return (
          <form>
            <ul>
              <li>
                <Textbox
                  labelText="Write your career "
                  value={career}
                  placeholder="e.g. extra information"
                  name="career"
                  onChange={(event) => {setCareer(event.target.value)}}
                />
                <span>{career}</span>
              </li>
              <li>
                <Textbox
                  labelText="Write your experience"
                  value={experience}
                  placeholder="e.g. extra information"
                  name="experience"
                  onChange={(event) => {setExperience(event.target.value)}}
                />
                <span>{experience}</span>
              </li>
              <li>
                <Textbox
                  labelText="Additional information"
                  value={additionalInformation}
                  placeholder="e.g. extra information"
                  name="additionalInformation"
                  onChange={(event) => {setAdditionalInformation(event.target.value)}}
                />
                <span>{additionalInformation}</span>
              </li>
            </ul>
          </form>
        );
      }

  const App = () => {
    return (
      <div className="App">
        <Form />
      </div>
    );
  }

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

CodePudding user response:

The key things are:

  1. Use useState to manage the state of the component. In my example I've just called the state data which you can initialise with an empty object, which you can update with the setData function.

  2. No more need to bind functions, and no more need to use this.

  3. No need for a render method. Just return the JSX.

Note 1: I also added in my own version of TextBox so I could provide a working example. It meant that you could get rid the ul/li markup and make it a bit tidier.

const { useEffect, useState } = React;

function TextBox(props) {

  const {
    label,
    name,
    value,
    placeholder,
    handleChange
  } = props;
  
  return (
    <fieldset>
      <legend>{label}</legend>
      <input
        value={value}
        name={name}
        placeholder={placeholder}
        onChange={handleChange}
      />
    </fieldset>
  );
}

function Form({ initialState }) {

  // Set up useState using the initialState to
  // initialise it
  const [data, setData] = useState(initialState);

  // When the handler is called extract the
  // value and name, and use the name as a dynamic
  // key when you update the state. Here we create a new
  // state by spreading out the old state, and adding the new
  // property
  function handleChange(e) {
    const { name, value } = e.target;
    setData({ ...data, [name]: value });
  }

  return (
    <form>
      <TextBox
        label="Career"
        value={data.career}
        name="career"
        placeholder="e.g. Doctor"
        handleChange={handleChange}
      />
      <TextBox
        label="Experience"
        value={data.experience}
        name="experience"
        placeholder="e.g. Two years"
        handleChange={handleChange}
      />
      <TextBox
        label="Additional information"
        value={data.additionalInformation}
        name="additionalInformation"
        placeholder="Anything else we should know"
        handleChange={handleChange}
      />
    </form>
  );
}

// Set the initialState
const initialState = {
  career: 'Doctor',
  experience: 'Two years',
  additionalInformation: 'n/a'
}

// Pass the initialState into `Form`
// as a property
function App() {
  return (
    <div>
      <Form initialState={initialState} />
    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('react')
);
fieldset { display: inline; margin-bottom: 0.3em; background-color: #efefef; }
input { width: 300px }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related