0

I have a react native app and i'm trying to update a Date in a custom context.

ThemeContext

export const ThemeContext = React.createContext({
    theme: 'dark',
    toggleTheme: () => { },
    date: new Date(),
    setDate: (date: Date) => { } 
});

Basic context with the date and the function to update it

App.tsx

export default class App extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      theme: 'dark',
      date: new Date()
    };
  }

  render() {
    const { theme, date } = this.state;
    const currentTheme = themes[theme];

    const toggleTheme = () => {
      const nextTheme = theme === 'light' ? 'dark' : 'light';
      this.setState({ theme: nextTheme });
    };

    const setDate = (date: Date) => {
      // ERROR is raised HERE
      this.setState({date: date});
    }

    return (
      <>
        <IconRegistry icons={EvaIconsPack} />
        <ThemeContext.Provider value={{ theme, toggleTheme, date, setDate }}>
          ...
        </ThemeContext.Provider>
      </>
    );
  }
}

I simply hava a state with a Date and create a setDate function. I wrapped my app into the context provider.

Picker

class PickerContent extends React.Component<{}, ContentState> {
    static contextType = ThemeContext;

    constructor(props: {} | Readonly<{}>) {
        super(props);
        let currentMode = 'date';
        let show = false;

        if (Platform.OS === 'ios') {
            currentMode = 'datetime';
            show = true;
        }

        this.state = {
            date: new Date(),
            mode: currentMode,
            show: show
        };
    }

    setMode(currentMode: string) {
        this.setState({ mode: currentMode, show: true });
    };

    onChange(_event: any, selectedDate: Date) {
        const currentDate = selectedDate || this.state.date;
        // I update the context here
        this.context.setDate(currentDate);
        
        this.setState({date: currentDate, show: Platform.OS === 'ios'})
    }

    render() {
        const {show, date, mode } = this.state;
        const color = 'dark';

        return (
            <>
            ...
            {show && <DateTimePicker
                ...
                onChange={(event, selectedDate) => this.onChange(event, selectedDate)}>
        </DateTimePicker>}</>
        )
    }
}

I use the lib 'DateTimePicker' to choose a date and bind the onChange to update the context. This picker is on a modal.

So the warning appears when the onChange function of DateTimePicker is trigger. The error is on the setState of App.tsx (in setDate)

Warning: Cannot update during an existing state transition (such as within 'render'). Render methods should be a pure function of props and state.

Would you know how to correct this error?

EDIT :

I was using a Modal component from the UI Kitten library. I switch to the react native Modal and the error is gone. It seems that the error comes from the Library. SORRY

thank you in advance for your help, Sylvain

2 Answers2

0

If you're using class component, what you can do is to move the context update fn inside componentDidUpdate. You just compare your states, if your state has changed, you update your context with the new value. Something along the lines of:

componentDidUpdate(prevProps, prevState) {
  if (prevState.date !== this.state.date) {
    this.context.setDate(this.state.date);
  }
}

onChange(_event: any, selectedDate: Date) {
    const currentDate = selectedDate || this.state.date;
    
    this.setState({date: currentDate, show: Platform.OS === 'ios'})
}

This way you're not updating your context during render.

If you refactor this component to functional, you would be able to do the same thing using useEffect.

Konstantin
  • 1,390
  • 6
  • 18
  • I, thanks for your answer. I tried to do what you said but i have the same error. The error It's happening inside the App component not the Picker. So i think the mistake is on the app class – Sylvain Dupuy Feb 08 '21 at 11:28
  • It was my understanding that you pointed to the line of `setDate` inside your picker. I cannot know which line brings you the problem, so please update your question accordingly. – Konstantin Feb 08 '21 at 12:40
  • I said at then end of my question : "So the warning appears when the onChange function of DateTimePicker is trigger. The error is on the setState of App.tsx (in setDate)". isn't it clear? – Sylvain Dupuy Feb 08 '21 at 13:33
  • I update the code to see which line exactly raised the error – Sylvain Dupuy Feb 08 '21 at 13:44
  • I revised your code again, why do you have your fns inside render? Please convert them to methods (remove the `consts`, you are using Class, not Functional component), move them outside of Render, pass them using the `this` to your context, and please tell me the result of combining this plus the previous answer. – Konstantin Feb 08 '21 at 14:03
0

I edited my question. The error finally seems to come from the library used (ui kitten).