简体   繁体   中英

How can I update the parent state by calling a function within a switch in my stateless component ?

My goal is to update the state of my parent component with only a portion of data from the initial Json

So basically if for example the case text get triggered:

1- I return the desired text and render it in my component (I succeeded in doing that)

2- I also want to take this specific data and store it in the parent state

3- I will later use this data to create a form

I tried many things, I finally managed to update the state of the parent by passing down a function to the stateless function MyFunction , but I keep getting a warning because the setState is being called inside the render method of the parent Component

Warning: Cannot update during an existing state transition (such as within render or another component's constructor).

const MyFunction = props => {

   switch (props.type) {
       case 'image':
         return  props.json.data[props.key]
         break
       case 'text':
         props.changeParent(props.json.data[props.key])
         return props.json.data[props.key]
         break
       default:
         return "Empty text"
         break
  }
}

class UserComponent extends Component {
 constructor(props){
  super(props)
    this.state = {
     active: false
    }
 }

render(){
  return(
    <div>
      { MyFunction({ type: 'text', key: 'first_name', ...this.props }) }
      <img src={ MyFunction({ type: 'image', key: 'avatar', ...this.props }) } />
    </div>
   )
 }
}

// Parent Component
class App extends Component {
 constructor(props){
  super(props)
  this.state = {
    json:[],
    newJson: []
  }
}

// Fetching data from an api
componentDidMount(){
fetch("https://reqres.in/api/users/2")
   .then(response => response.json())
   .then(json => {
      this.setState({json: json })
 })
}

// Update the parent Json using the data sent from the 2nd child
changeParent(jsonToUpdate){
  this.setState({
    newJson :
       jsonToUpdate
    })
 }

render() {
  return (
    <div>
      <UserComponent {...this.state} changeParent={(jsonToUpdate) => this.changeParent(jsonToUpdate)}/>
    </div>
  );
 }
}

export default App;

Just use componentDidMount lifecycle method and maintain a state for the data returned by myFunction to avoid that warning like this

class UserComponent extends Component {
 constructor(props){
  super(props)
    this.state = {
     active: false,
     // this state stores the data returned by function
     myFunctionReturnData: ""
    }
 }

componentDidMount(){
  let myFunctionReturnData = MyFunction({ type: 'text', key: 'first_name', ...this.props });
  // Call the function and set the state by returned value
  this.setState({ myFunctionReturnData })
}
render(){
  return(
    <div>
      // Will render returned value when state will be set
      { this.state.myFunctionReturnData }
      <img src={ MyFunction({ type: 'image', key: 'avatar', ...this.props }) } />
    </div>
   )
 }
}

Update::

If you are calling MyFunction multiple times then you should avoid calling changeParent inside MyFunction because you are calling MyFunction inside render and calling changeParent inside render will put this in loop because you are updating parent state in changeParent function. A better solution i can think of according to given code is this

const MyFunction = props => {

   switch (props.type) {
       case 'image':
         return  props.json.data[props.key]
         break
       case 'text':
         // Remove changeParent from here
         return props.json.data[props.key]
         break
       default:
         return "Empty text"
         break
  }
}

And in componentDidMount use MyFunction to call the changeParent like

componentDidMount(){
  let myFunctionReturnData = MyFunction({ type: 'text', key: 'first_name', ...this.props });
  // Call the parent function
  this.props.changeParent(myFunctionReturnData)
}

You do not need to maintain any state now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM