Поднять состояние между компонентами в реакции

У меня проблема со связью между реагирующими компонентами. Я хочу передавать значения между компонентами «ProductNameSave.js» в «readJson.js». Значения из ProductNameSave.js получены из компонента windowForm.js. Из-за этой структуры ("windowForm.js" -> "ProductNameSave.js" -> "readJson.js") я думаю, что "ProductNameSave.js" является "источником истины". Вот компоненты. "windowForm.js"

import React from 'react';
import Input from '@material-ui/core/Input';
import UploadPicture from './UploadPicture.js';

export default class FormWindow extends React.Component{
    state  = {
        U_Factor:'',
        Solar_Heat_Gain_Coefficient:'',
        Visible_Transmittance:''
    };

    change = e =>{
        this.setState({
            [e.target.name]: e.target.value
        });
    };

    onSubmit= e =>{
        e.preventDefault();
        this.props.onSubmit(this.state);
        this.setState({
            U_Factor:'',
            Solar_Heat_Gain_Coefficient:'',
            Visible_Transmittance:''
        });
    };

    render(){
        return(
            <form className = "productForm">
                <Input 
                    name = "U_Factor"
                    placeholder = "U-Factor" 
                    value = {this.state.prodValue1} 
                    onChange = {e => this.change(e)}
                />
                <br />
                <Input 
                    name = "Solar_Heat_Gain_Coefficient"
                    placeholder = "Solar Heat Gain Coefficient"
                    value = {this.state.prodValue2} 
                    onChange = {e => this.change(e)}
                />
                <br />
                <Input 
                    name = "Visible_Transmittance"
                    placeholder = "Visible Transmittance" 
                    value = {this.state.prodValue3} 
                    onChange = {e => this.change(e)}
                />
                <br />
                <UploadPicture/>
               <button onClick = {e => this.onSubmit(e)}>Submit</button>
            </form>    
        )
    }
}

"ProductNameSave.js":

import React from 'react';
import FormWindow from './windowForm.js';


export default class ProductNameSave extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      field:'', 
      open: false
    };
  }

  state = {
    fields:{}
  };

  handleChance(fields){
    this.setState({fields})
  }

  onSubmit = (fields) => {
    this.setState({fields});
    console.info('App component got: ', fields);
  };

  render() {
    const fields = this.state.fields
    return (
      <div>
        <FormWindow  onSubmit  = {fields => this.onSubmit(fields)} />
      </div>
    );
  }
}

"readJson.js":

import React from 'react';
import MyAppChild from './readJsonChild.js';
import data from '../../model/data/ProductData/Material.json';
import ProductNameSave from '../ProductList/ProductNameSave.js';

export default class MyApp extends React.Component {

  constructor(props) {
    super(props);
    this.handleChangeEvent = this.handleChangeEvent.bind(this);
    this.state = {fields: ''};
  }

  handleChangeEvent(fields) {
    this.props.onValueChance({fields});
  }

  render() {
      const fields = this.props.fields;
      var json2 = data[0]      
      var arr = [];
      Object.keys(json2).forEach(function(key) {
        arr.push(json2[key]);
      });
    return 
      <ul>{arr.map(item => <MyAppChild key = {item.Name} Name = {item.Name} Roughness = {item.Roughness} Thickness = {item.Thickness} />)}</ul>;
      <ul><ProductNameSave onChance  = {fields => this.handleChangeEvent(fields)}/></ul>;
  }
}

readJson.js получает значения из отдельного компонента. Цель состоит в том, чтобы передать значения из windowForm.js через ProductNameSave в readJson, чтобы заменить значения в reaJson новыми значениями из ProductNameSave. Если я запускаю код, я получаю следующую ошибку: Ошибка: MyApp.render (): должен быть возвращен действительный элемент React (или null). Возможно, вы вернули undefined, массив или другой недопустимый объект.

Есть ли у кого-нибудь идеи, как я могу решить эту проблему?

Заранее большое спасибо!

🤔 А знаете ли вы, что...
React обеспечивает реактивное обновление интерфейса при изменении состояния.


924
3

Ответы:

Проблема в readJson.js. То, как этот компонент возвращает JSX, неверен. В React 15 каждый компонент JSX-элемента должен быть заключен в div или span и т. д.

Проверьте обновленный код ниже

import React from 'react';
import MyAppChild from './readJsonChild.js';
import data from '../../model/data/ProductData/Material.json';
import ProductNameSave from '../ProductList/ProductNameSave.js';

export default class MyApp extends React.Component {

  constructor(props) {
    super(props);
    this.handleChangeEvent = this.handleChangeEvent.bind(this);
    this.state = {fields: ''};
  }

  handleChangeEvent(fields) {
    this.props.onValueChance({fields});
  }

  render(){
    const fields = this.props.fields;
      var json2 = data[0]      
      var arr = [];
      Object.keys(json2).forEach(function(key) {
        arr.push(json2[key]);
      });
    let children = [];
    arr.map((item, i) => {
        children.push(<MyAppChild key = {item.Name} Name = {item.Name} Roughness = {item.Roughness} Thickness = {item.Thickness} />);
    });
return(
    <div>
        <ul>
        {children}
        </ul>
        <ul><ProductNameSave onChance  = {fields => this.handleChangeEvent(fields)}/></ul>
    </div>
    )
}
}

если ваш компонент возвращает один элемент jsx, тогда их не нужно заключать между div или span, если более одного элемента jsx, тогда они должны быть заключены.


Вы также можете использовать <React.Fragment>, если используете версию React> 16. Это позволяет избежать добавления другого элемента в DOM только для группировки других элементов JSX.

<React.Fragment>
    <ul>{arr.map(item => <MyAppChild key = {item.Name} Name = {item.Name} Roughness = {item.Roughness} Thickness = {item.Thickness} />)}</ul>;
    <ul><ProductNameSave onChance  = {fields => this.handleChangeEvent(fields)}/></ul>;
</React.Fragment>

Ссылка: Документ ReacJS для фрагмента.

Существует еще одна сокращенная версия ReactJS, которая пока не поддерживается другими инструментами. То же самое можно прочитать на приведенной выше странице документа.


Не пытайтесь поднять состояние из windowForm.js через ProductNameSave до readJson, это антипатерн. Вместо этого вы можете сделать следующее:

  1. Определите состояние в родительском компоненте (в вашем случае это, вероятно, компонент readJson), а также определите метод, который изменит состояние и будет передан дочернему компоненту (в вашем случае windowForm.js). Как только вы определите такой метод и передадите его дочернему компоненту, вы сможете вызвать этот метод внутри дочернего компонента, и этот метод изменит состояние в родительском компоненте.

ИЛИ

  1. Используйте Redux и храните свои данные в глобальном состоянии. Эти данные будут доступны во всех ваших компонентах.