javascript - Map of React Components not re rendering on State Change - Stack Overflow

I have a Setup where i have a map of React Components which needs to shown in view.Also there are many

I have a Setup where i have a map of React Components which needs to shown in view.

Also there are many input select handlers which update the parent ponent state but after the state update the Parent Component render method is called but the Child Component doesn't refresh the Values .

What am i missing here ? I am bit confused

A minimal Reproduction of the Problem Stackblitz.

import React, { PureComponent } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';

export const ReactExample = ({ name, value, handleChange }) => (
  <select name={name} value={value} onChange={handleChange}>
    <option value="A">Apple</option>
    <option value="B">Banana</option>
    <option value="C">Cranberry</option>
  </select>
)

const Section = props => {
  return (
    <div>
      {props.header}
      <br />
      {props.primaryNode}
      <br />
      {props.bottom}
    </div>
  );
};


class App extends React.PureComponent {

  state = {
    current: 'B'
  };
  constructor(props) {
    super(props);
  }

  show = [5, 6, 3, 5, 7, 8, 77, 8, 90];

  primaryNode = () => {
    const filterData = this.show;

    return (<div>{filterData}----{this.state.current} // doesn't get updated even though state updates after dropdown</div>);
  };

  bottom = () => {
    return (
      <ReactExample name="fruit" value={this.state.current} handleChange={this.handleChange} />

    )
  }

  handleChange = (event) => {
    console.log(event.target.value); // always logged and state updated with no change in value
    this.setState({ current: event.target.value });
  }

  data = ["A", "B", "C"];

  map = {
    "A": (<Section primaryNode={this.primaryNode()} bottom={this.bottom()} header={"A"} />),
    "B": (<Section primaryNode={this.primaryNode()} header={"B"} />),
    "C": (<Section primaryNode={this.primaryNode()} header={"C"} />)
  };

  render() {
    return (<div>{this.data.map(d => this.map[d])}</div>)
  }
}

render(<App />, document.getElementById('root'));

I have a Setup where i have a map of React Components which needs to shown in view.

Also there are many input select handlers which update the parent ponent state but after the state update the Parent Component render method is called but the Child Component doesn't refresh the Values .

What am i missing here ? I am bit confused

A minimal Reproduction of the Problem Stackblitz.

import React, { PureComponent } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';

export const ReactExample = ({ name, value, handleChange }) => (
  <select name={name} value={value} onChange={handleChange}>
    <option value="A">Apple</option>
    <option value="B">Banana</option>
    <option value="C">Cranberry</option>
  </select>
)

const Section = props => {
  return (
    <div>
      {props.header}
      <br />
      {props.primaryNode}
      <br />
      {props.bottom}
    </div>
  );
};


class App extends React.PureComponent {

  state = {
    current: 'B'
  };
  constructor(props) {
    super(props);
  }

  show = [5, 6, 3, 5, 7, 8, 77, 8, 90];

  primaryNode = () => {
    const filterData = this.show;

    return (<div>{filterData}----{this.state.current} // doesn't get updated even though state updates after dropdown</div>);
  };

  bottom = () => {
    return (
      <ReactExample name="fruit" value={this.state.current} handleChange={this.handleChange} />

    )
  }

  handleChange = (event) => {
    console.log(event.target.value); // always logged and state updated with no change in value
    this.setState({ current: event.target.value });
  }

  data = ["A", "B", "C"];

  map = {
    "A": (<Section primaryNode={this.primaryNode()} bottom={this.bottom()} header={"A"} />),
    "B": (<Section primaryNode={this.primaryNode()} header={"B"} />),
    "C": (<Section primaryNode={this.primaryNode()} header={"C"} />)
  };

  render() {
    return (<div>{this.data.map(d => this.map[d])}</div>)
  }
}

render(<App />, document.getElementById('root'));

Share Improve this question asked Nov 17, 2019 at 21:15 Rahul SinghRahul Singh 19.7k13 gold badges68 silver badges94 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 1

The class field map is initialized only once, at first ponent render. It does not really matter that you change the state, that variable holds the very same data and does not change in time.

One of the solutions would be moving that variable into render:

render() {
    const map = {
        "A": (<Section primaryNode={this.primaryNode()} bottom={this.bottom()} header={"A"} />),
        "B": (<Section primaryNode={this.primaryNode()} header={"B"} />),
        "C": (<Section primaryNode={this.primaryNode()} header={"C"} />)
    };

    return (<div>{this.data.map(d => this.map[d])}</div>)
}

or you could transform map field into a method:

map = () => ({
    "A": (<Section primaryNode={this.primaryNode()} bottom={this.bottom()} header={"A"} />),
    "B": (<Section primaryNode={this.primaryNode()} header={"B"} />),
    "C": (<Section primaryNode={this.primaryNode()} header={"C"} />)
});

render() {
    return (<div>{this.data.map(d => this.map()[d])}</div>)
}

So the data returned by map is always up-to-date.

I think you're making this more confusing than it needs to be by holding all these values as class properties. The reason that they are not updating is because this.map is only defined once. You don't need map at all, just render your nodes directly inside render function which gets called on state changes:

render() {
  return (
    <div>
      <Section primaryNode={this.primaryNode()} bottom={this.bottom()} header={"A"} />
      <Section primaryNode={this.primaryNode()} header={"B"} />
      <Section primaryNode={this.primaryNode()} header={"C"} />
    </div>
  )
}

And if you really want it to be a map, then define it inside render:

render() {
  const map = {
    "A": <Section primaryNode={this.primaryNode()} bottom={this.bottom()} header={"A"} />,
    "B": <Section primaryNode={this.primaryNode()} header={"B"} />,
    "C": <Section primaryNode={this.primaryNode()} header={"C"} />
  };

  return <div>{this.data.map(d => map[d])}</div>
}

Not entirely sure what you're wanting to do, but it sounds like you want your A/B/C values to be updated with state-change. The problem is that you are defining the primaryNode in your map-object before render(), rather than inside of render() (which always re-renders when state changes. Try this:

import React, { PureComponent } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';

const Section = item => (
  <>
    <br/>
    <section>
      {item.header}
      <br />
      {item.primaryNode}
      <br />
      {item.bottom}
    </section>
  </>
);

class App extends React.PureComponent {
  constructor(props) {
    super(props);
  }

  state = {
    current: 'B'
  }

  data = ["A", "B", "C"];
  show = [5, 6, 3, 5, 7, 8, 77, 8, 90];

  bottom = () => (
    <select name={"fruit"} value={this.state.current} onChange={this.handleChange}>
      <option value="A">Apple</option>
      <option value="B">Banana</option>
      <option value="C">Cranberry</option>
    </select>
  );

  handleChange = (event) => (
    this.setState({ current: event.target.value })
  );

  primaryNode = () => (
    <div className="primary-node">
      {this.show} ---- {this.state.current}
    </div>
  );

  render() {
    return (
      <>
        State Value - {this.state.current}
        <br/>
        <br/>
        <br/>
        {this.data.map(el => (
          <Section 
            bottom={el === "A" && this.bottom()}
            header={el}
            primaryNode={this.primaryNode()}
          />
        ))}
      </>
    );
  }
}

render(<App />, document.getElementById('root'));

Try moving the map inside the render() method. render() is fired when the state changes so it's the place You're looking for

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744211307a4563345.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信