Sunday, 2 December 2018

React Context initial state is being mutated - JavaScript / React

I am making a guide me section. What this guide me section does - displays an array of processes. Within each process is an array of steps, within each step is an array of options. The user selects an option from one of the steps, it takes them to the next correlating step. If the user selects the option on step 2, it could take them to step 3 or back to step 1. It depends on the id.

With all that said I'm having issues with my Process mutating on me. I'm using React Context as a global state. When a user selects an option, I'm grabbing that id, then filtering the designated object by that id. So I should only be left is that processes with that specific step. What's happening is my initial global state is mutating somehow. I'm missing something here as I'm new to React.

P.s - I'm not using any services at this moment, so I just copied some JSON over to my initial state in context.js

context.js

import React, { Component } from 'react'
// import axios from 'axios'

const Context = React.createContext()
const reducer = (state, action) => {
    switch(action.type){
        case 'SEARCH_PROCESS':
        return {
            ...state,
            guides: action.payload
        }
        default:
        return state
    }
}

export class Provider extends Component {

    state = {
        guides: [
            {
                "processName": "Support Messaging",
                "steps": [{
                    "id": "15869594739302",
                    "title": "step one", 
                    "options": [{
                        "nextStep": "4767fn-47587n-2819am-9585j,04956840987", 
                        "text": "Option 1 text", 
                        "type": "option"
                      },
                      {
                        "nextStep": "4767fn-47587n-2819am-9585j,04956840987", 
                        "text": "Option 2 text",
                        "type": "option"
                      },
                      {
                        "nextStep": "", 
                        "text": "Option 3 text",
                        "type": "option"
                      }
                    ]
                  },
                  {
                    "id": "04956840987",
                    "title": "step two", 
                    "options": [{
                        "nextStep": "4767fn-47587n-2819am-9585j,15869594739302",
                        "text": "Return to step1", 
                        "type": "option"
                      },
                      {
                        "nextStep": "", 
                        "text": "Option 2 text",
                        "type": "option"
                      },
                      {
                        "nextStep": "",
                        "text": "Option 3 text",
                        "type": "option"
                      }
                    ]
                  }
                ],
                "owner": "bob",
                "id": "4767fn-47587n-2819am-9585j",
                "lastUpdated": 154222227099000, 
                "tags": ["Tag1", "Tag2", "Tag3"]
              }
                ],
                "owner": "bob",
                "id": "4767fn-47587n-2819am-9585x",
                "lastUpdated": 154222227099000, 
                "tags": ["Tag1", "Tag2", "Tag3"]
              }
        ],
        initialGuide: [
            {
                "processName": "Support Messaging",
                "steps": [{
                    "id": "15869594739302",
                    "title": "step one", 
                    "options": [{
                        "nextStep": "4767fn-47587n-2819am-9585j,04956840987", 
                        "text": "Option 1 text", 
                        "type": "option"
                      },
                      {
                        "nextStep": "4767fn-47587n-2819am-9585j,04956840987", 
                        "text": "Option 2 text",
                        "type": "option"
                      },
                      {
                        "nextStep": "", 
                        "text": "Option 3 text",
                        "type": "option"
                      }
                    ]
                  },
                  {
                    "id": "04956840987",
                    "title": "step two", 
                    "options": [{
                        "nextStep": "4767fn-47587n-2819am-9585j,15869594739302",
                        "text": "Return to step1", 
                        "type": "option"
                      },
                      {
                        "nextStep": "", 
                        "text": "Option 2 text",
                        "type": "option"
                      },
                      {
                        "nextStep": "",
                        "text": "Option 3 text",
                        "type": "option"
                      }
                    ]
                  }
                ],
                "owner": "bob",
                "id": "4767fn-47587n-2819am-9585j",
                "lastUpdated": 154222227099000, 
                "tags": ["Tag1", "Tag2", "Tag3"]
              }
        ],

        dispatch: action => this.setState(state => reducer(state, action))
    }



    render() {
        return (
            <Context.Provider value={this.state}>
                {this.props.children}
            </Context.Provider>
        )
  }
}

export const Consumer = Context.Consumer;

Guides.js

import React, { Component } from 'react'
import { Consumer } from '../../context'
import Process from './Process'

class Guides extends Component {
  constructor (props) {
    super(props)
    this.state = {
      contextValue: [],
      searchData: props.location.data
    }
  }

  render () {
      console.log(this.props.location.data, this.state, 'logging state and props on guides')
    //   this.state.searchData = this.props.location.data

    return (
      <Consumer>
        {value => {

          return (
            <React.Fragment>
              <div className="content-wrapper">
                <h1>Guide Me</h1>
                <div className="ms-Grid times--max-width" dir="ltr">
                  <div className="ms-Grid-row">
                    <div className="profile--wrapper ms-Grid-col ms-sm12 ms-md12 ms-lg5">
                      {value.guides.map(item => {
                        return <Guide key={item.id} guide={item} processValue={value.guides} initialGuide={value.initialGuide}/>
                      })}
                    </div>
                  </div>
                </div>
              </div>
            </React.Fragment>
          )
        }}
      </Consumer>
    )
  }
}

export default Guides

Process.js

import React, { Component } from 'react'
import GuideSteps from './Guide-Steps'
import { Consumer } from '../../context'

class Process extends Component {
  constructor(props) {
    super(props)
    this.state = {
      processName: this.props.guide.processName,
      process: this.props.guide,
      steps: this.props.guide.steps,
      selectedIndex: 0,
      selectedStep: '',
      processValue: this.props.processValue,
      initialGuide: this.props.initialGuide
    }

    this.displayStep = this.displayStep.bind(this)
  }

  displayStep = (res, dispatch) => {
    this.setState({ selectedStep: res })
  }

  render() {

    const { steps, selectedIndex, process, processName, processValue, initialGuide } = this.state


    return (
        <Consumer>
          {value => {
          return (
            <div>
              <h2 className="profile--sub-header--bold">{processName}</h2>

              <GuideSteps
                key={this.props.guide.steps[selectedIndex].id}
                selectedStep={this.props.guide.steps[selectedIndex]}
                stepValue={this.displayStep}
                process={process}
                processValue={processValue}
                initialGuide={initialGuide}
              />
            </div>
          )
          }}
          </Consumer>
          )

  }
}

export default Process

Guide-Steps.js

import React, { Component } from 'react'
import { ChoiceGroup } from 'office-ui-fabric-react/lib/ChoiceGroup'
import { Consumer } from '../../context'

class GuideSteps extends Component {

    constructor(props) {
        super(props);
        this.state = {
            process: [],
            selectedStep: this.props.selectedStep,
            dispatch: '',
            processValue: this.props.processValue,
            initialGuide: ''
        }

        this._onChange = this._onChange.bind(this)
    }

  _onChange = (ev, option) => {
    // this.props.stepValue(option.value.nextStep)
    const { dispatch , initialGuide } = this.state

    let optionArray = option.value.nextStep.split(',')

    let processArray = this.state.process.filter(item => {
        return item.id === optionArray[0]
    })

    let stepArray = processArray[0].steps.filter(item => {
        return item.id === optionArray[1]
    })

    console.log(stepArray, processArray, this.state.process, 'logging step array before setting')

    processArray[0].steps = stepArray

    console.log(stepArray, processArray, this.state.process, 'logging step array after setting')


    dispatch({
        type: 'SEARCH_PROCESS',
        payload: processArray
      })
  }

  render() {
    let options = []
    {
      this.props.selectedStep.options.map(item => {
        return options.push({
          key: item.text,
          text: item.text,
          value: item
        })
      })
    }
    return (
        <Consumer>
            {value => {
                const { dispatch, guides, initialGuide } = value
                this.state.dispatch = dispatch
                console.log(value, 'logging initial guide in render')
                this.state.process = initialGuide
    return (
      <div>
        <ChoiceGroup
          className="defaultChoiceGroup"
          options={options}
          onChange={this._onChange}
        />
      </div>
    )
    }}
    </Consumer>
    )
  }
}

export default GuideSteps

On change in GuideSteps is where I'm doing the logic for filtering and setting up my new object.



from React Context initial state is being mutated - JavaScript / React

No comments:

Post a Comment