Home > Enterprise >  React Component rewrites parent's state
React Component rewrites parent's state

Time:11-25

i'm pretty new at React so i need some help i have an component which has structure smth like that

class App extends React.Component{
     constructor(props) {
        super(props);
        this.state = {
            ...
            portfolio: []
            ...
        }
        ...
        this.userDataUpdatesSubscribe = this.userDataUpdatesSubscribe.bind(this);
        this.dealComplete = this.dealComplete.bind(this);
        ...
    }
async componentDidMount() {
        ...
        await this.userDataUpdatesSubscribe();
        ...
    }
userDataUpdatesSubscribe(){
//fs here is a Firebase Firestore SDK
//firebase.initializeApp(firebaseConfig);
//const fs = firebase.firestore();
        fs.collection('users').doc(...).onSnapshot(
            e => {
                this.portfolioInit(e.data().portfolio).then(v =>
                    this.setState({
                        portfolio: v,
                        ...
                    })
                );
            }
        );
    }
async portfolioInit(stocks){
        let a = [];
        for (const v of stocks) {
            let i;
                await this.getPrice(v.ticker).then(e => {
                    i = e.trade.p
                });
            a.push({
                ticker: v.ticker,
                name: StocksData[v.ticker].name,
                price: await i,
                avgPrice: v.avgPrice,
                count: v.count
            });
        }
        return a;
    }
async getPrice(ticker, date=null){
        let a;
        let u = ...;
        await fetch(
            u,
            {
                ...
            }
        ).catch(() => {...}).then(
             async e => {
                a = await e.json();
            }
        )
        return await Promise.resolve(a);
    }
render(){
   <...>
      <TheProblemComponent p={this.state.portfolio} .../>
   </...>
}
} 

so i have a component where state updates on firestore snapshot. i don't store prices in database but i need it so i use getPrice method which returns me price. when i've got all prices the state updates. then i convey data to which has structure like

const TheProblemComponent = (p) => {
  const makeDeal() => {
    let x = p.p;
    ...
    some calculations
    ...
    for(let i = 0; i < x.lenght; i  ){
      x[i] = {
         ticker: x[i].ticker,
         avgPrice: x[i].avgPrice,
         count: x[i].count
      } // so here i just delete price and name properties which are from props
    }
    fs.collection('users').doc(...).update({portfolio: x, ...}).then(() => {
       ...some actions
    })
  }
  return <Button
           onClick={() => {console.log(p.p); makeDeal()}}
         ></Button>
}

so again. i have a parent component which state updates on firestore snapshot. portfolio in database has avgPrice, count and ticker. in my component it also has price which i receive from the getPrice method and name which is constant. this state portfolio i send to ProblemComponent as props which should not modify the parent's state but it does. console.log() prints array without price and name even when executes before makeDeal function. i've tried to store price and name in DB but i want not to do it

CodePudding user response:

It appears you are mutating the parent state via the passed prop because you are mutating the p prop.

const makeDeal() => {
  let x = p.p; // <-- saved reference to p.p (portfolio??)

  ...
  some calculations
  ...

  for(let i = 0; i < x.lenght; i  ){
    x[i] = { // <-- mutation!!
      ticker: x[i].ticker,
      avgPrice: x[i].avgPrice,
      count: x[i].count
    }
  }

  fs.collection('users')
    .doc(...)
    .update({ portfolio: x, ... })
    .then(() => {
      ...some actions
    });
}

To resolve, shallow copy the data you want to update. I suggest also using more descriptive variable names so the code is more readable.

const makeDeal() => {
  const portfolio = [...p.p]; // <-- copy array into new array reference

  ...
  some calculations
  ...

  for(let i = 0; i < portfolio.length; i  ){
    portfolio[i] = { // <-- update the copy
      ticker: portfolio[i].ticker,
      avgPrice: portfolio[i].avgPrice,
      count: portfolio[i].count
    }
  }

  fs.collection('users')
    .doc(...)
    .update({ portfolio, ... })
    .then(() => {
      ...some actions
    });
}
  • Related