最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React.js - Create input elements from JSON schema - Stack Overflow

programmeradmin0浏览0评论

I'm looking for advice on the best way to dynamically create elements from JSON in React using mapping with ponents.

I figure we can have each input type as a separate ponent class and construct the element passing in props and bind the changes.

E.g. the JSON:

    {
        "type": "text",
        "name": "FirstName",                    
        "class": "text",
        "placeholder": "Enter first name"
    },
    {
        "type": "text",
        "name": "Surname",                  
        "class": "text",
        "placeholder": "Enter surname"
    },

React:

class InputText extends React.Component {
  constructor(props) {
    super(props);
    this.changeValue = this.changeValue.bind(this);
  }

  render() {
    return (
      <div className={className}>
        <label htmlFor={this.props.name}>{this.props.title}</label>
        <input
          onChange={this.changeValue}
          name={this.props.name}
          type={this.props.type}
          value={this.props.value}
        />
      </div>
    );
  }
}

Any advice on the best way to iterate through (and validate) each item in the JSON? Am I on the right track here? Thanks!

I'm looking for advice on the best way to dynamically create elements from JSON in React using mapping with ponents.

I figure we can have each input type as a separate ponent class and construct the element passing in props and bind the changes.

E.g. the JSON:

    {
        "type": "text",
        "name": "FirstName",                    
        "class": "text",
        "placeholder": "Enter first name"
    },
    {
        "type": "text",
        "name": "Surname",                  
        "class": "text",
        "placeholder": "Enter surname"
    },

React:

class InputText extends React.Component {
  constructor(props) {
    super(props);
    this.changeValue = this.changeValue.bind(this);
  }

  render() {
    return (
      <div className={className}>
        <label htmlFor={this.props.name}>{this.props.title}</label>
        <input
          onChange={this.changeValue}
          name={this.props.name}
          type={this.props.type}
          value={this.props.value}
        />
      </div>
    );
  }
}

Any advice on the best way to iterate through (and validate) each item in the JSON? Am I on the right track here? Thanks!

Share Improve this question edited Dec 10, 2017 at 17:39 Paul Redmond asked Dec 10, 2017 at 15:19 Paul RedmondPaul Redmond 3,2964 gold badges35 silver badges53 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 2

You need a ponent that maps over the data and returns the collection of InputTexts. Here I've called it Main.

class Main extends React.Component {
  render() {

    // Map over the data and return the pleted ponent
    // On each iteration pass in the object data as `params`.
    // You can deconstruct this in the `InputText` ponent
    return data.map((input, i) => {
      return <InputText key={i} params={input} />
    });
  }
}

Now you can pick up those params in the ponent by deconstructing this.props.params and using those variables to fill out the ponent.

class InputText extends React.Component {

  constructor(props) {
    super(props);
    this.changeValue = this.changeValue.bind(this);
  }

  changeValue() {
    console.log('Placeholder to prevent bug');
  }

  render() {

   // Use destructuring to grab the individual properties from params
   const { type, name, classname, placeholder } = this.props.params;

    // Use those properties in the returned ponent elements
    return (
      <div className={classname}>
        <label htmlFor={name}>Test</label>
        <input
          onChange={this.changeValue}
          name={name}
          type={type}
          placeholder={placeholder}
        />
      </div>
    );
  }
}

DEMO

InputText.jsx

Upon interaction each InputText will raise onChange saying which input field was edited and what is its current value.

import * as React from 'react';

export class InputText extends React.Component {
  onChange = (e) => {
    const {onChange, name} = this.props;
    const {value} = e.target;
    if (onChange) {
      onChange(name, value);
    }
  }

  render() {
    const {name, title, type, placeholder, className, value} = this.props;
    return (
      <div className={className}>
        <label htmlFor={name}>{title}</label>
        <input
          placeholder={placeholder}
          name={name}
          type={type}
          value={value}
          onChange={this.onChange}
        />
      </div>
    );
  }
}

Form.jsx

Here we maintain the state of all inputs. The weird reduce is done to initialise the shape of the state with the input names being the object properties.

// initial state
{
  "FirstName": "",
  "Surname": ""
}

Upon edit this.setState({[name]: value}) the associated property gets updated.

import * as React from 'react';
import { InputText } from './InputText';

const inputs = [{
  "type": "text",
  "title": "some title",
  "name": "FirstName",
  "class": "text",
  "placeholder": "Enter first name"
}, {
  "type": "text",
  "title": "some other title",
  "name": "Surname",
  "class": "text",
  "placeholder": "Enter surname"
}];

export class Form extends React.Component {
  constructor(props) {
    super(props);
    this.state = inputs.reduce((acc, input) => {
      return {...acc, [input.name]: ''};
    }, {})
  }

  onChange = (name, value) => {
    this.setState({[name]: value});
  }

  render() {
    const list = inputs.map(input => {
      return (
        <InputText
          value={this.state[input.name]}
          key={input.name}
          type={input.type}
          name={input.name}
          title={input.title}
          className={input.class}
          placeholder={input.placeholder}
          onChange={this.onChange}
      />
      );
    });

    return (
      <form>
        {list}
      </form>
    );
  }
}

Assuming the JSON you want to iterate through is provided in an array you could do something like this. It will create a label and input element for each JSON.

render() {
  return (
    <div className={className}>
      {
      this.props.yourArray.map(value=>(
        <label htmlFor={value.name}>{value.title}</label>
        <input
          onChange={this.changeValue}
          name={value.name}
          type={value.type}
          value={value.value}
        />
      ))
      }
    </div>
  );
}
发布评论

评论列表(0)

  1. 暂无评论