Search code examples
javascriptreactjsjavascript-objectscomputed-properties

Initialize state with dynamic key based on props in reactJS


How to initialize state with dynamic key based on props? The props is a data fetched from external source (async). So the props will change when the data is succesfully downloaded. Consider a component like this.

edit: I want to make the state dynamic because I want to generate a dialog (pop up) based on the item that is clicked. the DialogContainer is basically that. visible prop will make that dialog visible, while onHide prop will hide that dialog. I use react-md library.

class SomeComponent extends React.Component {
  constructor() {
    super();
    this.state = {};
    // the key and value will be dynamically generated, with a loop on the props
    // something like:
    for (const item of this.props.data) {
      this.state[`dialog-visible-${this.props.item.id}`] = false}
    }
  }

  show(id) {
    this.setState({ [`dialog-visible-${id}`]: true });
  }

  hide(id) {
    this.setState({ [`dialog-visible-${id}`]: false });
  }

  render() {
    return (
      <div>
        {this.props.data.map((item) => {
          return (
            <div>
              <div key={item.id} onClick={this.show(item.id)}>
                <h2> Show Dialog on item-{item.id}</h2>
              </div>
              <DialogContainer
                visible={this.state[`dialog-visible-${item.id}`]}
                onHide={this.hide(item.id)}
              >
                <div>
                  <h1> A Dialog that will pop up </h1>
                </div>
              </DialogContainer>
            </div>
          );
        })}
      </div>
    )
  }
}

// the data is fetched by other component.
class OtherComponent extends React.Component {
  componentDidMount() {
    // fetchData come from redux container (mapDispatchToProps)
    this.props.fetchData('https://someUrlToFetchJSONData/')
  }
}

The data then is shared via Redux.

However, based on my understanding so far, state can be updated based on props with componentWillReceiveProps or the new getDerivedStateFromProps (not on the constructor as above). But, how to do that on either method?

The example here only explains when the state is initialized on the constructor, and call setState on either cWRP or gDSFP. But, I want the key value pair to be initialized dynamically.

Any help/hint will be greatly appreciated. Please do tell if my question is not clear enough.


Solution

  • import React from 'react';
    import {connect} from 'react-redux';
    import {yourAction} from '../your/action/path';
    
    class YourClass extends React.Component {
        state = {};
    
        constructor(props){
            super(props);
        }
    
        componentDidMount(){
            this.props.yourAction()
        }
    
        render() {
            const {data} = this.props; //your data state from redux is supplied as props.
    
            return (
                <div>
                    {!data ? '' : data.map(item => (
                        <div>{item}</div>
                    ))}
                </div>
            )
        }
    }
    
    function mapStateToProps(state) {
        return{
            data:state.data //state.data if that is how it is referred to in the redux. Make sure you apply the correct path of state within redux
        }
    }
    
    export default connect(mapStateToProps, {yourAction})(YourClass)
    

    If you do this, <div>{item}</div> will change as you change the data state. The idea is to just map the redux state to your class props - you don't have to map the props back to the state. The render() automatically listens to changes in props supplied by redux. However, if you do want to somehow know redux state change in events, you can add the following functions.

    componentWillReceiveProps(newProps){
        console.log(newProps)
    }
    
    getDerivedStateFromProps(nextProps, prevState){
        console.log(nextProps);
        console.log(prevState);
    }