Calling functions after state change occurs in reactjs
Asked Answered
C

3

16

My question is this. I have two components. First component is an image cropper. Second component is the one that i should display the cropped image.

The problem i'm facing is i can pass the cropped image to my second component but i have to press the button that crops the image and pass to the second component, twice. On the second click only my image is passing to the second component. But i can display the cropped image in the first component only by one click. I think it is happening because in reactjs state changes are not occurring immediately. So how can i fix this.

My approach was to create a prop function in the 1st component as this.props.croppedImage(this.state.preview.img); here this.state.preview.img is the cropped image. And in the 2nd component i'm getting the cropped image by calling the prop function.

My code

1st component (cropper)

class CropperTest extends React.Component {

    constructor(props) {

        super(props);

        this.state = {
            name: "beautiful",
            scale: 1,
            preview: null,
       }

        this.handleSave = this.handleSave.bind(this);

    }

    handleSave = () => {

        const img = this.editor.getImageScaledToCanvas().toDataURL();

        this.setState({
            preview: {
                img,
                scale: this.state.scale,
            }
        })

        this.props.croppedImage(this.state.preview.img);

    }

    setEditorRef = (editor) => {
        this.editor = editor
    }

    render() {
        return (
            <div>
                <div className="overlay"></div>

                <div className="crop_div">
                    <AvatarEditor
                        image={this.props.cropImage}
                        ref={this.setEditorRef}
                        width={450}
                        height={450}
                        border={50}
                        color={[255, 255, 255, 0.6]} // RGBA
                        scale={this.state.scale}
                        rotate={0}
                    />
                </div>



                <div className="zoom_slider text_align_center">
                    <input className="crop_btn" type='button' onClick={this.handleSave} value='Save'/>

                </div>

            </div>
        )
    }
}

export default CropperTest;

2nd component

Here i'm basically doing the following.

  <CropperTest  croppedImage = {this.getCroppedImg}/>

    getCroppedImg(img){

            alert("Perfect Storm");
            this.setState({

                previewImg:img

            })

        }
Cladophyll answered 1/9, 2017 at 2:49 Comment(4)
setState accepts a second parameter as a callback function for when the state has been updated. Try it out!Kaylee
Also, no need to pre-bind your class methods if you’re declaring them like method = () => {}Decided
@Decided thanks but it is not the root of my problemCladophyll
Yes. Hence why I made a comment and not an answer.Decided
H
25

I think it is happening because in reactjs state changes are not occurring immediately. So how can i fix this?

From the React#setState,

setState(updater, [callback])

setState() enqueues changes to the component state. The setState doesn't immediately update the state. setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall.Instead, use componentDidUpdate or a setState callback (setState(updater, callback))

Call the this.props.croppedImage in the setState callback.You will get updated values of component state. In your case its this.state.preview

this.setState({
  preview: {
    img,
    scale: this.state.scale,
  }
}, () => {
  this.props.croppedImage(this.state.preview.img);
})
Hartmunn answered 1/9, 2017 at 4:16 Comment(0)
L
12

Callbacks are no longer supported in setState. The best way to go about this is to use a useEffect and set the dependency variable to the state variable.

useEffect(() => {
   //do operation on state change
},[stateVariable])
Leucite answered 12/1, 2022 at 17:56 Comment(3)
Wrong answer, that is class component, not React with Hooks. Answer is not gonna work in given situation.Comatulid
If you are still using class components in 2022, it is high time to make the switch. They are pretty much losing support.Leucite
Afaik, there is no other work around for this. So if this helps someone, I am going to let it be.Leucite
S
0

Can confirm useEffect is the way to go now - https://reactjs.org/docs/hooks-effect.html

Sike answered 16/8, 2022 at 5:24 Comment(1)
This is a "thanks" for https://mcmap.net/q/718563/-calling-functions-after-state-change-occurs-in-reactjs Isn't it? For that you should use your privileges for voting or commenting.Listlessness

© 2022 - 2024 — McMap. All rights reserved.