0

Here is what I am trying to do and examples I have found don't seem to set the value either. So I am sure it is something simple I am over-looking.

setViewedSubmission(subId: string) {
    logger.log("pre:", this.state.position.candidates.find((c)=> {
        return c.submissionId == subId
    }).viewedSubmission) //returns original value

    this.state.position.candidates.find((c)=> {
        return c.submissionId == subId
    }).viewedSubmission = true //expect the value to update
    this.forceUpdate()

    logger.log("post:", this.state.position.candidates.find((c)=> {
        return c.submissionId == subId
    }).viewedSubmission) //returns original value still
}

This is what I actually started with but also doesn't work: Based on the responses, this is closer to what I should be doing but still doesn't. What is the issue here?

 let pos = Object.assign({}, this.state.position)
    pos.candidates.find((c) => {
        return c.submissionId == subId
    }).viewedSubmission = true;

    this.setState({ position: pos })
1
  • This is what I actually started with but also doesn't work: Based on the responses, this is closer to what I should be doing but still doesn't. What is the issue here? let pos = Object.assign({}, this.state.position) pos.candidates.find((c) => { return c.submissionId == subId }).viewedSubmission = true; this.setState({ position: pos }) Commented Aug 15, 2018 at 17:13

3 Answers 3

1

The only way to update the state and get the screen re-rendered is to use the setState method. Here a look:

let candidates = this.state.position.candidates;
candidates = candidates.map(candidate => {
    if(candidate.submissionId === subId) candidate.viewedSubmission = true;
    return candidate;
});
this.setState(prevState => ({
    position: {
        ...prevState.position,
        candidates
    }
}));
Sign up to request clarification or add additional context in comments.

2 Comments

This is what I arrived at yesterday before seeing your code... and it works like I wanted. Just wasn't sure how to dig down. And my solution is VERY close to yours! this.setState(currentState => ({ ...currentState, position: { ...currentState.position, candidates: currentState.position.candidates.map((c) => ({ ...c, viewedSubmission: (c.submissionId === subId ? true : c.viewedSubmission) })) } }))
Cool! But you don’t need to add ...currentState. The method knows that it has to update the state like we do with ˋObject.assign`
1

I think you're looking at this backwards. React is basically a state machine which means the UI reflects the current status of the state.

Without delving too deep into your code you probably want to structure things something similar to the following:

class Demo extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      viewed: false,
    }
  }
  someBusinessLogic(viewed) {
    this.setState({
      ...this.state,
      viewed: viewed,
    })
  }

  render() { 
    const { viewed } = this.state
    if (viewed ) {
     return <div>VIEWED</dive>
    } else {
     return <div>UNVIEWED</div>
    }
  }
}

...and somewhere else

...//this is terrible code, just an example of using the business logic
  <Demo viewed='true' ref={r => this.demo1 = r} />
  <Demo viewed='false'/>

  <button onClick={e => { this.demo1.someBusinessLogic('viewed') }}>Set Viewed = 'viewed'</button>
...

Structuring the component this way means that you reflect upon the state rather than trying to manage when updates occur. setState(newState) will re-render if the state is different.

My guess is that the internal state of your component is the same.

If I misread your question and you are not seeing updates passed to the component make sure you are using the key and that it is updating or override shouldComponentUpdate which is where forceUpdate starts to be useful.

Hopefully this helps, you might consider providing more details about your implementation so the community can be more specific.

2 Comments

Daniel, I edited my original post to show what I started with.
@JohnKochJR You didn't include enough code to reproduce the issue (include your render method) . My best guess is that when you set state you're not actually changing anything. I would strongly suggest looking at a simple Redux tutorial to get a sense of how state works: reactjs.org/tutorial/tutorial.html The new tutorials are really in-depth and give you a nice example. If you provide more information I can try to help. Also, try logging to the console so you can see when things happen. That might help you understand it. Log the render method
0

You can't alter state directly. It is immutable (If you plan on working with React, you should read more about that). When you say this.state.value = 1, it won't update. Instead, you should do this.setState({ value: 1 }). And, if there are more itens in state, you should do this.setState(p => ({ ...p, value: 1 }), since when you update state, you must return the entire new state object.

2 Comments

That all makes perfect sense and I knew that but read somewhere that you could set it this way. Guess that was wrong. So the state structure is like this: state { someValue: "", objArray[]: {} } And I am wanting to update the value in objArray based on a matching value inside. objArray = [{ key:1, value: "a" }, { key: 2, value: "b"}] and I want to update the object that matches key == 2 I can't seem to figure out how to do that within the setState function.
Filipe, I edited my original post to show what I started with. But also doesn't work

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.