Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reactjs -- parent, child - state handling architecture for each

Tags:

reactjs

I am working on a reactjs website that will feature an array of items to populate a table.

The parent shell will pull down a list of available records into an array -- and using a child component I want to populate the table rows with this data.

I've started to create the child component - but the properties fed by the parent were not being processed until I placed the state handling near the render function.

I did have a constructor in the child component setting states but it didn't seen the way to go -- should I set the state in componetDidMount or componentWillMount (-- if a new child is made?)

The child component will have buttons -- save, generate, cancel -- that need to then alter the initial loaded states -

//rules the parent can create/remove children - from an array -- the child needs to take the initial values given by the parent - but then act independent from it - so the child can take the initial properties and then with the buttons inside it - make its own calls. The application is already bound by this parent array and that's causing malfunctions.

-- child needs to be able to be able to cancel - e.g. revert back to its original state before saved -- so if its touched - isDirty is then true. -- an old child - isNew: false - pre-existing data - only shows a save button. Only the name is editable -- a new child -- isNew: true -- will at first show a generate button (save hidden) -- the generate button will be hidden and save will be shown if the user manually starts to enter data into the name field. -- the generate/save buttons are disabled until the user has selected a region.

https://codesandbox.io/embed/frosty-vaughan-kdl1v should look something like this -- once the initial array has made the children - the parent should then only be able to Add blank children or remove new/old chidren -- all other states should then happen on the child level only -- cause you may have 3 new children, 5 old -- started changing values - some got saved, some got cancelled - independent changes..

parent

import React, { Component } from "react";

import Child from "./Child";
export default class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [
        {
          name: "apple",
          currentCode: "BJ3343",
          previousCode: " ",
          region: "opt2",
          isNew: false,
          isDirty: false
        },
        {
          name: "cherry",
          currentCode: "AS3433",
          previousCode: " ",
          region: "opt1",
          isNew: false,
          isDirty: false
        }
      ]
    };
  }

  addChild() {
    let blank = {
      name: "xxxxxxxxxxxxxxx",
      code: "",
      region: "",
      isNew: true,
      isDirty: true
    };

    this.state.list.push(blank);
  }

  render() {
    return (
      <div>
        <button onClick={this.addChild()}>Add Child</button>
        <button>Remove Child</button>
        <table>
          <thead>
            <tr>
              <td />
              <td>Region</td>
              <td>Code</td>
              <td>Name</td>
              <td>save/generate</td>
              <td>cancel</td>
            </tr>
          </thead>
          <tbody>
            {this.state.list.map((item, index) => {
              return (
                <Child
                  key={index}
                  index={index}
                  item={item}
                />
              );
            })}
          </tbody>
        </table>
      </div>
    );
  }
}

child

//import ReactDOM from 'react-dom';
import React, { Component } from "react";

export default class Child extends Component {
  generateCode = index => {
    //does an api call -- and then on success alters the value of the code
    //Make an api call here and suppose api call return code 213
    const responseCode = 231;
    return responseCode;
  };

  saveCode = index => {
    //does an api call -- and then on success makes the child isDirty: false, isNew: false
  };

  cancel = index => {
    //reverts states for this child
  };

  render() {
    const index = this.props.index;
    const { name, region, currentCode, isNew, isDirty } = this.props.item;

    return (
      <tr>
        <td>
          <input type="checkbox" name="selection" />
        </td>
        <td>
          <select disabled={!isNew} type="input" name="region" value={region}>
            <option value="">Select</option>
            <option value="opt1">opt1</option>
            <option value="opt2">opt2</option>
            <option value="opt3">opt3</option>
            <option value="opt4">opt4</option>
          </select>
        </td>
        <td>
          <input disabled={!isNew} type="input" value={currentCode} />{" "}
        </td>
        <td>
          <input type="input" name="name" value={name} />
        </td>
        <td>
          <button onClick={() => this.generateCode(index)}>Generate</button>
          <button onClick={() => this.saveCode(index)}>Save</button>
        </td>

        <td>
          <button onClick={() => this.cancel(index)}>Cancel</button>
        </td>
      </tr>
    );
  }
}

//latest 30th Sep 2019 https://codesandbox.io/embed/elated-raman-twdqr

^ will add/remove children -- mock db array to delete for backend

//latest 1st oct 2019 https://codesandbox.io/s/stupefied-hodgkin-iyj43 - latest version - more stable

like image 486
The Old County Avatar asked Nov 07 '22 13:11

The Old County


1 Answers

You need to move state upwards to the parent and access it in the child from the parent as illustrated in the updated answer. More details can be found here Lifting up state official reactJS documentation. Or you can use centralised state management libraries like redux or mobx.

class Parent extends React.Component {
//define your parent as well as child state here. 
state={
  parentState={...},
  childState={name: '', region: ''}
}

handleChange = (newValues) => {
  this.setState({childState: newValues});
  // fetch data here and update it to the state
  fetch(){}
}

componentDidMount(){
  //fetch side effects here like data fecthing and setting state isLoading false here using setState
}

render() {
  if (this.state.isLoading){
    return (
      <p>Loading</p>
    )
  }
  return (
    <div>
      {
        this.state.cart.map((item, key) =>
            <Child key={item.id}
                name=item.name
                region=item.region
                values: {this.state.childState}
                handleChange={this.handleChange}
            />
        );
      }
    </div>
  );
}
}


class Parent extends React.Component {
render() {
  // directly access data using props instead of state
  // pass the updated value upwards to the parent via this.props.handleChange(newValue)(depends on your implementation)
  // Access new value in the child in next render by this.props.childState
  return (
    <div>
      <p>Name: {this.props.values.name}</p>
      <p>Region: {this.props.values.region}</p>
    </div>
  );
}
}
like image 154
uneet7 Avatar answered Nov 15 '22 05:11

uneet7